sh recursive copy (cp -r) - Come escludere la sottocartella


8

Devo eseguire uno script remoto usando sshvia Ruby( net / ssh ) per copiare ricorsivamente una cartella ed escludere una sottocartella. Sto cercando il modo più veloce per farlo, quindi rsyncnon va bene. Inoltre, capisco che sshusa she non bash.

In bash faccio:

cp -r srcdir/!(subdir) dstdir

e funziona benissimo. Tuttavia quando avvio lo script tramite sshricevo l'errore

sh: 1: Syntax error: "(" unexpected

perché sta usando sh.

Ho controllato la shpagina man, ma non esiste alcuna opzione per escludere i file.

È la mia ipotesi di sshutilizzo shcorretto? Qualche suggerimento alternativo?

EDIT 1: Nel caso sia utile, l'output di sudo cat /etc/shellsè il seguente:

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

MODIFICA 2: OK. Quindi bash è disponibile e questo non sembra essere il problema. Ho verificato che l'ssh sta effettivamente usando bash. Il problema sembra essere legato alla fuga di parentesi o punto esclamativo. Ho provato a eseguire il comando dalla shell (macos) e questo è il comando effettivo:

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'

In questo modo ricevo un errore diverso

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

MODIFICA 3: In base ai commenti ho modificato l'aggiunta del mio comandoextglob

Se io uso

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'

Ricevo il seguente errore:

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

Se non sfuggo alla parentesi, ottengo

bash: -c: line 0: syntax error near unexpected token `('

3
ssh(bene sshd) usa la shell di login dell'utente remoto. Potrebbe essere qualsiasi cosa.
Stéphane Chazelas,

Unix non ha cartelle, solo directory. :)
tchrist,

1
In situazioni come questa spesso mi piace semplicemente sviluppare lo script sull'host remoto, quindi 1) lasciarlo lì, ssh in (programmaticamente se necessario) ed eseguirlo o 2) se cambia ogni volta, scp su, eseguire tramite ssh e poi cancellalo. Un passaggio in più, forse, ma non si finisce per sfuggire a incubi e globs che si espandono localmente invece che in remoto e tutto il resto. Altrimenti userei sempre il formato ereditario come usa @ StéphaneChazelas di seguito.
Josh Rumbut,

Risposte:


10

SSH esegue la shell di accesso sul sistema remoto, qualunque essa sia. Ma !(foo)richiede shopt -s extglob, che potresti non aver impostato sul telecomando.

Prova questo per vedere se SSH esegue Bash sul lato remoto:

ssh me@somehost 'echo "$BASH_VERSION"'

Se ciò stampa qualcosa, ma i tuoi script di avvio non vengono impostati extglob, puoi farlo manualmente sul comando passato a ssh:

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

extglob influenza l'analisi della riga di comando e ha effetto solo dopo una nuova riga, quindi dobbiamo inserire una nuova riga letterale, un punto e virgola non è sufficiente.

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

Inoltre, se sfuggi alla parentesi con barre rovesciate, perdono le loro proprietà speciali, come qualsiasi altro personaggio glob. Questo non è quello che vuoi fare in questo caso.

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

10

Non so perché pensi che rsync sia lento. La velocità di una copia è determinata principalmente dalla velocità del disco. Rsync ha molte opzioni per specificare ciò che vuoi includere ed escludere, quindi ti dà un controllo molto migliore rispetto al globbing della shell.

Come afferma il manuale bash, !(patter)viene riconosciuto in bash solo se extglobimpostato. Nel tuo esempio non hai impostato extglob. Inoltre, un bashiniziato come shè ancora bash, ma disabiliterà alcune estensioni per la compatibilità.

Il server SSH avvierà la shell di accesso dell'utente, come specificato in /etc/passwd. È possibile modificare la shell o utilizzare quella shell per avviare un'altra shell che si adatta meglio alle proprie esigenze.


Ho provato con time. time cp -r mesh/!(constant) N-> real 1.04s e time rsync -a mesh/ N --exclude=constant-> real 1.8s
Rojj

7
@Rojj è il confronto tra mele e arance. Per prima cosa, stai usando -a per rsync ma non per cp. Ciò comporta la conservazione delle autorizzazioni e di altri attributi, quindi in realtà non stai facendo la stessa cosa.
Carattere jolly

6

Alcune note prima:

  • il server ssh non inizia sha interpretare la riga di comando inviata dal client, ma esegue la shell di login dell'utente sull'host remoto, come that-shell -c <the-string-provided-by-the-client>. La shell di accesso dell'utente remoto potrebbe essere qualsiasi cosa. Tenete a mente che alcune conchiglie piace tcsh, fisho rcavere una sintassi molto diversa da quella di sh.
  • è davvero una riga di comando, o più esattamente una stringa (che può contenere caratteri di nuova riga, quindi diverse righe). Anche se si ssh host cmd arg1 'arg 2'dove cmd, arg1e arg 2sono tre argomenti passati a ssh, sshconcatena tali argomenti con gli spazi e in realtà invia la cmd arg1 arg 2stringa sshd, e la shell remota che avrebbe diviso in cmd, arg1, arge 2.
  • !(subdir)è un operatore glob (un kshoperatore glob supportato anche da zsh -o kshglobe bash -O extglob). Come tutti i globs, esclude i file nascosti, quindi attenzione ci potrebbero essere altri file che esclude.

Qui, per evitare il problema di scoprire la sintassi giusta per la shell remota, puoi effettivamente dire a quell'altra shell di avviare la shell desiderata e dargli il codice tramite stdin (una delle opzioni elencate in Come eseguire un semplice arbitrario comando su ssh senza conoscere la shell di accesso dell'utente remoto? )

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

bash -O extglob -O dotglobè una riga di comando che è capita allo stesso modo da tutte le principali shell, comprese quelle di tipo Bourne, csh, rc, fish ... Quanto sopra funzionerebbe fintanto che bashè installato ed è nell'utente $PATH(impostazione predefinita $PATH, eventualmente modificata dall'utente shell di login come con ~/.zshenvfor zsh, ~/.cshrcfor csh, ~/.bashrcfor bash).

POSIXly (anche se in pratica, potresti scoprire che più sistemi hanno un bashcomando che un paxcomando), potresti fare:

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

-sapplica le sostituzioni ai percorsi da trasferire. Quando tale sostituzione si espande in nulla, il file viene escluso. Il problema è che le sostituzioni si applicano anche al target dei symlink. Ecco perché usiamo .//.sopra per rendere meno probabile che un collegamento simbolico sia interessato.


4

Non credo sshsia limitato all'uso sh. Dipende piuttosto da ciò che è installato sul sistema di destinazione, da come è impostato l'utente e da quali shell sono consentite /etc/shells.

Hai considerato il chshcomando?


4

Se vuoi farlo in modo rapido, puoi guardare rsynccon un diverso algoritmo di crittografia. Questo ti dà la possibilità di escludere facilmente ecc., Senza sacrificare molto la velocità.

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

insieme all'aggiunta della arcfourcrittografia alla riga che inizia con Ciphersin /etc/ssh/ssh_config, se non è già abilitata, ti dà una velocità accettabile.

ATTENZIONE: la arcfourcrittografia non è sicura . NON eseguire questo su canali non sicuri. Se sei preoccupato per l'accesso al server da canali non sicuri tramite arcfourcrittografia, modifica la parte etc/ssh/ssh_configcon una parte specifica dell'host per l'host di origine: crea una Hostsezione in ssh_config per l'host di origine, puoi utilizzarla Ciphers arcfourper eseguire il mirroring dello -cswitch precedente , che limita la arcfourcrittografia solo a questo host.

Per i dettagli, consultare le ssh_configpagine man.

Tuttavia, se le tue CPU supportano il set di istruzioni AES-NI, prova a passare a aes128-gcm@openssh.com (sì, questo è il nome della cifra, incluso @ stuff), che utilizzerà AES128 incredibilmente veloce (con AES-NI) -GCM.

Quindi, con una CPU che supporta AES-NI, passare "ssh -T -c arcfour -o Compression=no -x"a "ssh -T -c aes128-gcm@openssh.com -o Compression=no -x"per risultati più sicuri.

Spiegazione

rsync

  • (Non usare -z, è molto più lento)
  • a: modalità archivio - riparatore, preserva il proprietario, conserva le autorizzazioni, conserva i tempi di modifica, conserva il gruppo, copia i collegamenti simbolici come collegamenti simbolici, preserva i file del dispositivo.
  • H: conserva i collegamenti reali
  • A: conserva gli ACL
  • X: conserva gli attributi estesi
  • x: non oltrepassare i limiti del file system
  • v: aumentare la verbosità
  • --numeric-ds: non mappare i valori uid / gid per nome utente / gruppo
  • se devi sincronizzare, aggiungi --delete: elimina i file estranei dalle directory dir (pulizia differenziale durante la sincronizzazione)
  • --progress: mostra l'avanzamento durante il trasferimento

SSH

  • T: disattiva pseudo-tty per ridurre il carico della cpu sulla destinazione.
  • c arcfour: usa la crittografia SSH più debole ma più veloce. È necessario specificare "Ciphers arcfour" in sshd_config sulla destinazione.
  • o Compression=no: Disattiva la compressione SSH.
  • x: disattiva l'inoltro X se è attivato per impostazione predefinita.

Il manzo è nelle sshopzioni: se usi solo rsync -ave la -e ssh -T -c arcfour -o Compression=no -x"parte, puoi ottenere anche queste velocità.


Confronto:

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

Fonti :

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

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


3
Bene, sembrano funzionare cp -rall'interno del sistema remoto, quindi la crittografia utilizzata dalla connessione SSH non è davvero rilevante. In ogni caso arcfourè considerato piuttosto rotto e OpenSSH lo disabilita insieme ad altri sul server per impostazione predefinita dalla versione 6.7 (2014-10-06) . In ogni caso, ssh -o Ciphers='aes128-ctr'mi dà circa 90 MB / s, che dovrebbe essere abbastanza veloce su un collegamento da 1 Gbit / s.
ilkkachu,

Sì, l'arcfour è rotto, ma in questo caso non dovrebbe essere una shell SICURA, ma una "shell più comoda" senza enfasi sulla crittografia. Non userei questo su connessioni non sicure, è corretto. Se 'aes128-ctr' è abbastanza veloce, può e dovrebbe essere usato invece.
emk2203,

Vedi anche la mia risposta estesa per l'utilizzo con CPU che supportano AES-NI.
emk2203,

2

Secondo i miei calcoli, la copia completa più veloce usa sempre 'tar' (qui assumendo GNU taro compatibile).

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

E tarha moltissime opzioni per manipolare attributi, permessi e selezione / esclusione di file. Ad esempio, il comando precedente esclude la sottocartella di livello superiore denominata .thumbcache durante la copia.


Si noti che --exclude=.thumbcacheesclude tutti i .thumbcachefile, non solo quello di livello superiore. Con GNU tar(no bsdtar), è possibile utilizzare --exclude=./.thumbcacheper escludere solo il .thumbcachefile di livello superiore .
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.