sh recursive copy (cp -r) - Comment exclure un sous-dossier

8

J'ai besoin d'exécuter un script distant en utilisant sshvia Ruby( net / ssh ) pour copier récursivement un dossier et exclure un sous-dossier. Je cherche le moyen le plus rapide de le faire donc ce rsyncn'est pas bon. Aussi, je comprends que cela sshutilise shet non bash.

En bash je fais:

cp -r srcdir/!(subdir) dstdir

et ça marche bien. Cependant, lorsque je lance le script via, sshje reçois l'erreur

sh: 1: Syntax error: "(" unexpected

car il utilise sh.

J'ai vérifié la shpage de manuel, mais il n'y a pas d'option pour exclure des fichiers.

Est-ce ma supposition d' sshutiliser shcorrectement? Une autre suggestion?

EDIT 1: Si cela est utile, la sortie de sudo cat /etc/shellsest la suivante:

# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/usr/bin/tmux
/usr/bin/screen

EDIT 2: OK. Alors bash, il est disponible et cela ne semble pas être le problème. J'ai vérifié que le ssh utilise réellement bash. Le problème semble être lié à la fuite de parenthèses ou d'exclamation. J'ai essayé d'exécuter la commande à partir du shell (macos) et voici la commande réelle:

ssh -i .ssh/key.pem ubuntu@X.X.X.X 'mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant'

De cette façon, je reçois une erreur différente

cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory

EDIT 3: Sur la base des commentaires, j'ai changé ma commande en ajoutantextglob

Si j'utilise

ssh -i .ssh/key.pem ubuntu@X.X.X.X 'shopt -s extglob; mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant'

Je reçois l'erreur suivante:

cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory

Si je n'échappe pas à la parenthèse, je reçois

bash: -c: line 0: syntax error near unexpected token `('
Rojj
la source
3
ssh(enfin sshd) utilise le shell de connexion de l'utilisateur distant. Ça pourrait être n'importe quoi.
Stéphane Chazelas
Unix n'a pas de dossiers, seulement des répertoires. :)
tchrist
1
Dans des situations comme celle-ci, j'aime souvent simplement développer le script sur l'hôte distant, puis soit 1) le laisser là, ssh dans (par programme si nécessaire) et l'exécuter ou 2) s'il change à chaque fois, le parcourir, l'exécuter via ssh, puis supprimez-le. Une étape supplémentaire peut-être, mais vous ne vous retrouvez pas avec des cauchemars et des globes en fuite qui se développent localement au lieu de à distance et tout ça. Sinon, j'utiliserais toujours le format heredoc comme @ StéphaneChazelas utilise ci-dessous.
Josh Rumbut

Réponses:

10

SSH exécute votre shell de connexion sur le système distant, quel qu'il soit. Mais !(foo)nécessite shopt -s extglob, que vous n'avez peut-être pas réglé sur la télécommande.

Essayez ceci pour voir si SSH exécute Bash du côté distant:

ssh me@somehost 'echo "$BASH_VERSION"'

Si cela imprime quelque chose, mais que vos scripts de démarrage ne sont pas définis extglob, vous pouvez le faire à la main à l'aide de la commande passée à ssh:

ssh me@somehost 'shopt -s extglob
    echo srcdir/!(subdir)'                                 
 # or
ssh me@somehost $'shopt -s extglob\n echo srcdir/!(subdir)'   

extglob affecte l'analyse de la ligne de commande, et ne prend effet qu'après une nouvelle ligne, nous devons donc y mettre une nouvelle ligne littérale, un point-virgule ne suffit pas.

ssh me @ somehost 'shopt -s extglob; echo srcdir /! (subdir) '

Ce n'est pas non plus que si vous échappez à la parenthèse avec des barres obliques inverses, ils perdent leurs propriétés spéciales, comme tous les autres caractères globaux. Ce n'est pas ce que vous voulez faire dans ce cas.

$ touch foo bar; shopt -s extglob; set +o histexpand
$ echo *
bar foo
$ echo !(foo)
bar
$ echo \*
*
$ echo !\(foo\)
!(foo)
ilkkachu
la source
10

Je ne sais pas pourquoi vous pensez que rsync serait lent. La vitesse d'une copie est principalement déterminée par la vitesse du disque. Rsync a de nombreuses options pour spécifier ce que vous voulez inclure et exclure, il vous donne donc un bien meilleur contrôle que la globalisation du shell.

Comme l'indique le manuel bash, le !(patter)est uniquement reconnu dans bash si extglobest défini. Dans votre exemple, vous n'avez pas défini extglob. De plus, un a bashcommencé tel shquel bash, mais désactivera certaines extensions pour des raisons de compatibilité.

Le serveur SSH démarre le shell de connexion de l'utilisateur, comme spécifié dans /etc/passwd. Vous pouvez soit changer le shell, soit utiliser ce shell pour démarrer un autre shell qui correspond mieux à vos besoins.

RalfFriedl
la source
J'ai testé avec time. time cp -r mesh/!(constant) N-> réel 1,04 et time rsync -a mesh/ N --exclude=constant-> réel 1,8
Rojj
7
@Rojj c'est la comparaison des pommes aux oranges. D'une part, vous utilisez -a pour rsync mais pas pour cp. Cela implique la préservation des autorisations et d'autres attributs, vous ne faites donc pas la même chose.
Wildcard
6

Quelques notes d'abord:

  • le serveur ssh ne commence pas shà interpréter la ligne de commande envoyée par le client, il exécute le shell de connexion de l'utilisateur sur l'hôte distant, comme that-shell -c <the-string-provided-by-the-client>. Le shell de connexion de l'utilisateur distant peut être n'importe quoi. Gardez à l' esprit que certains coquillages comme tcsh, fishou rcune syntaxe très différente de celle de sh.
  • c'est vraiment une ligne de commande, ou plus exactement une chaîne (qui peut contenir des caractères de nouvelle ligne, donc plusieurs lignes). Même si vous faites ssh host cmd arg1 'arg 2'cmd, arg1et arg 2sont trois arguments transmis ssh, sshconcatène ces arguments avec des espaces et envoie en fait la cmd arg1 arg 2chaîne à sshdet shell distant fendrait que dans cmd, arg1, arget 2.
  • !(subdir)est un opérateur glob (un kshopérateur glob également pris en charge par zsh -o kshglobet bash -O extglob). Comme tous les globes, il exclut les fichiers cachés, donc méfiez-vous qu'il peut y avoir d'autres fichiers qu'il exclut.

Ici, pour éviter le problème de trouver la bonne syntaxe pour le shell distant, vous pouvez réellement dire à cet autre shell de démarrer le shell que vous voulez et de lui donner le code via stdin (l'une des options répertoriées dans Comment exécuter un simple arbitraire commande sur ssh sans connaître le shell de connexion de l'utilisateur distant? )

ssh host 'bash -O extglob -O dotglob' << 'EOF'
cp -r srcdir/!(subdir) dstdir/
EOF

bash -O extglob -O dotglobest une ligne de commande qui est comprise de la même manière par tous les principaux shells, y compris ceux de type Bourne, csh, rc, fish ... Ce qui précède fonctionnerait tant qu'il bashest installé et est dans l'utilisateur $PATH(par défaut $PATH, éventuellement modifié par l'utilisateur) login shell comme avec ~/.zshenvfor zsh, ~/.cshrcfor csh, ~/.bashrcfor bash).

POSIXly (bien qu'en pratique, vous pouvez trouver que plus de systèmes ont une bashcommande qu'une paxcommande), vous pouvez faire:

ssh host sh << 'EOF'
cd srcdir && pax -rw -'s|^\.//\./subdir\(/.*\)\{0,1\}$||' .//. /path/to/destdir/
EOF

-sapplique des substitutions aux chemins transférés. Lorsque cette substitution se développe à rien, le fichier est exclu. Le problème est que les substitutions s'appliquent également à la cible des liens symboliques. C'est pourquoi nous utilisons .//.ci-dessus pour réduire la probabilité qu'un lien symbolique soit affecté.

Stéphane Chazelas
la source
4

Je ne pense pas que ce sshsoit limité à l'utilisation sh. Cela dépend plutôt de ce qui est installé sur le système cible, de la configuration de l'utilisateur et des shells autorisés /etc/shells.

Avez-vous pensé à la chshcommande?

RudiC
la source
4

Si vous voulez le faire rapidement, vous pouvez regarder rsyncavec un algorithme de cryptage différent. Cela vous donne la possibilité d'exclure facilement etc., sans sacrifier beaucoup de vitesse.

rsync -aHAXxv --numeric-ids --progress -e "ssh -T -c arcfour -o Compression=no -x" user@<source>:<source_dir> <dest_dir>

avec l'ajout du arcfourcryptage à la ligne commençant par Ciphersin /etc/ssh/ssh_config, s'il n'est pas déjà activé, vous donne une vitesse acceptable.

AVERTISSEMENT: le arcfourcryptage n'est pas sécurisé . Ne l'exécutez PAS sur des canaux non sécurisés. Si vous êtes préoccupé par l'accès au serveur à partir de canaux non sécurisés à l'aide du arcfourchiffrement, modifiez le etc/ssh/ssh_configavec une partie spécifique à l'hôte pour votre hôte source - Créez une Hostsection dans votre ssh_config pour votre hôte source, vous pouvez l'utiliser Ciphers arcfourpour refléter le -ccommutateur ci-dessus , qui restreint le arcfourchiffrement à cet hôte uniquement.

Pour plus de détails, reportez-vous aux ssh_configpages de manuel.

Cependant, si vos processeurs prennent en charge le jeu d'instructions AES-NI, essayez de passer à [email protected] (oui, c'est le nom du chiffrement, y compris les éléments @), qui utilisera le AES128 extrêmement rapide (avec AES-NI) -GCM.

Donc, avec un processeur prenant en charge AES-NI, passez "ssh -T -c arcfour -o Compression=no -x"à "ssh -T -c [email protected] -o Compression=no -x"pour des résultats plus sécurisés.

Explication

rsync

  • (Ne pas utiliser -z, c'est beaucoup plus lent)
  • a: mode archive - rescursif, préserve le propriétaire, préserve les autorisations, préserve les temps de modification, préserve le groupe, copie les liens symboliques en tant que liens symboliques, préserve les fichiers de périphérique.
  • H: conserve les liens physiques
  • A: conserve les ACL
  • X: conserve les attributs étendus
  • x: ne franchissez pas les limites du système de fichiers
  • v: augmenter la verbosité
  • --numeric-ds: ne mappez pas les valeurs uid / gid par nom d'utilisateur / groupe
  • si vous devez synchroniser, ajoutez --delete: supprimez les fichiers superflus des répertoires dest (nettoyage différentiel pendant la synchronisation)
  • --progress: montrer les progrès pendant le transfert

ssh

  • T: désactiver le pseudo-tty pour diminuer la charge du processeur sur la destination.
  • c arcfour: utilisez le cryptage SSH le plus faible mais le plus rapide. Doit spécifier "Ciphers arcfour" dans sshd_config sur la destination.
  • o Compression=no: Désactivez la compression SSH.
  • x: désactiver le transfert X s'il est activé par défaut.

Le boeuf est dans les sshoptions - si vous utilisez simplement rsync -avla -e ssh -T -c arcfour -o Compression=no -x"pièce, vous pouvez également obtenir ces vitesses.


Comparaison:

  • 13,6 Mo / s rsync -az
  • 16,7 Mo / s scp -Cr
  • 44,8 Mo / s rsync -a
  • 59,8 Mo / s sftp
  • 61,2 Mo / s scp -r
  • 61,4 Mo / s sftp -R 128 -B 65536
  • 62,4 Mo / s rsync -a -P -e "ssh -T -c arcfour -o Compression=no -x"
  • 143,5 Mo / s scp -r -c arcfour
  • 144,2 Mo / s sftp -oCiphers=arcfour

Sources :

https://gist.github.com/KartikTalwar/4393116

http://nz2nz.blogspot.com/2018/05/rsync-scp-sftp-speed-test.html

emk2203
la source
3
Eh bien, ils semblent fonctionner cp -rdans le système distant, donc le cryptage utilisé par la connexion SSH n'est pas vraiment pertinent. Dans tous les cas arcfourest considéré comme plutôt cassé et OpenSSH le désactive avec d'autres sur le serveur par défaut depuis la version 6.7 (2014-10-06) . Dans tous les cas, cela ssh -o Ciphers='aes128-ctr'me donne environ 90 Mo / s, ce qui devrait être assez rapide sur une liaison à 1 Gbit / s.
ilkkachu
Oui, arcfour est cassé, mais ce n'est pas censé être un shell SÉCURISÉ pour ce cas, mais plus «shell confortable» sans accent sur le cryptage. Je ne l'utiliserais pas sur des connexions non sécurisées, c'est exact. Si 'aes128-ctr' est assez rapide, il peut et doit être utilisé à la place.
emk2203
Voir également ma réponse étendue pour une utilisation avec des processeurs prenant en charge AES-NI.
emk2203
2

Selon mes calculs, la copie complète la plus rapide utilise toujours 'tar' (en supposant ici GNU tarou compatible).

mkdir -p photos2 &&
  tar -C photos -cf - --exclude=./.thumbcache . |
  tar -C photos2 -xpf -

Et tardispose d'une tonne d'options pour manipuler les attributs, les autorisations et la sélection / exclusion de fichiers. Par exemple, la commande ci-dessus exclut le sous-dossier de niveau supérieur appelé .thumbcache lors de la copie.

Lam Das
la source
Notez que cela --exclude=.thumbcacheexclut tous les .thumbcachefichiers, pas seulement celui du niveau supérieur. Avec GNU tar(pas bsdtar), vous pouvez utiliser --exclude=./.thumbcachepour exclure uniquement le .thumbcachefichier de niveau supérieur .
Stéphane Chazelas