sh rekursive Kopie (cp -r) - So schließen Sie einen Unterordner aus

8

Ich muss ein Remote-Skript mit sshvia Ruby( net / ssh ) ausführen, um einen Ordner rekursiv zu kopieren und einen Unterordner auszuschließen. Ich suche nach dem schnellsten Weg, also rsyncist es nicht gut. Auch ich verstehe das sshnutzt shund nicht bash.

In Bash mache ich:

cp -r srcdir/!(subdir) dstdir

und es funktioniert gut. Wenn ich das Skript jedoch über sshstarte, erhalte ich den Fehler

sh: 1: Syntax error: "(" unexpected

weil es benutzt sh.

Ich habe die shManpage überprüft , aber es gibt keine Möglichkeit, Dateien auszuschließen.

Ist es meine Annahme ssh, shrichtig zu verwenden? Irgendein alternativer Vorschlag?

EDIT 1: Falls es nützlich ist, ist die Ausgabe von sudo cat /etc/shellsder folgenden:

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

EDIT 2: OK. Bash es ist verfügbar und das scheint nicht das Problem zu sein. Ich habe überprüft, dass der SSH tatsächlich verwendet bash. Das Problem scheint mit dem Entkommen von Klammern oder Ausrufezeichen zu tun zu haben. Ich habe versucht, den Befehl über die Shell (MacOS) auszuführen, und dies ist der eigentliche Befehl:

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'

Auf diese Weise erhalte ich einen anderen Fehler

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

EDIT 3: Basierend auf den Kommentaren habe ich meinen Befehl zum Hinzufügen geändertextglob

Wenn ich benutze

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'

Ich erhalte folgende Fehlermeldung:

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

Wenn ich der Klammer nicht entkomme, bekomme ich

bash: -c: line 0: syntax error near unexpected token `('
Rojj
quelle
3
ssh(gut sshd) verwendet die Login-Shell des Remote-Benutzers. Könnte alles sein.
Stéphane Chazelas
Unix hat keine Ordner, nur Verzeichnisse. :)
Tchrist
1
In solchen Situationen entwickle ich das Skript oft nur auf dem Remote-Host und lasse es entweder 1) dort, ssh in (bei Bedarf programmgesteuert) und führe es aus oder 2) wenn es sich jedes Mal ändert, scp es über, führe es aus es über ssh, und löschen Sie es dann. Ein zusätzlicher Schritt vielleicht, aber Sie werden nicht Albträumen und Klumpen entkommen, die sich lokal ausdehnen, anstatt aus der Ferne und so weiter. Ansonsten würde ich immer das Heredoc-Format verwenden, wie es @ StéphaneChazelas unten verwendet.
Josh Rumbut

Antworten:

10

SSH führt Ihre Login-Shell auf dem Remote-System aus. Benötigt !(foo)aber shopt -s extglob, was Sie möglicherweise nicht auf der Fernbedienung eingestellt haben.

Versuchen Sie dies, um festzustellen, ob SSH Bash auf der Remote-Seite ausführt:

ssh me@somehost 'echo "$BASH_VERSION"'

Wenn dadurch etwas gedruckt wird, Ihre Startskripte jedoch nicht festgelegt sind extglob, können Sie dies mit dem folgenden Befehl manuell tun ssh:

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

extglob wirkt sich auf das Parsen der Befehlszeile aus und wird erst nach einer neuen Zeile wirksam. Daher müssen wir dort eine wörtliche neue Zeile einfügen. Ein Semikolon reicht nicht aus.

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

Auch nicht, dass, wenn Sie der Klammer mit Backslashes entkommen, sie ihre besonderen Eigenschaften verlieren, wie alle anderen Glob-Zeichen. Dies ist in diesem Fall nicht das, was Sie tun möchten.

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

Ich weiß nicht, warum Sie denken, dass rsync langsam sein würde. Die Geschwindigkeit einer Kopie wird hauptsächlich durch die Geschwindigkeit der Festplatte bestimmt. Rsync bietet viele Optionen zum Festlegen, was eingeschlossen und ausgeschlossen werden soll, sodass Sie eine viel bessere Kontrolle haben als beim Shell-Globbing.

Wie im Bash-Handbuch angegeben, !(patter)wird das in Bash nur erkannt, wenn extglobes eingestellt ist. In Ihrem Beispiel haben Sie nicht festgelegt extglob. Außerdem wird a bashwie shimmer gestartet gestartet bash, einige Erweiterungen werden jedoch aus Kompatibilitätsgründen deaktiviert.

Der SSH-Server startet die Anmeldeshell des Benutzers wie in angegeben /etc/passwd. Sie können entweder die Shell ändern oder diese Shell verwenden, um eine andere Shell zu starten, die Ihren Anforderungen besser entspricht.

RalfFriedl
quelle
Ich habe mit getestet time. time cp -r mesh/!(constant) N-> echte 1.04s und time rsync -a mesh/ N --exclude=constant-> echte 1.8s
Rojj
7
@Rojj das ist Äpfel zu Orangen Vergleich. Zum einen verwenden Sie -a für rsync, aber nicht für cp. Dazu müssen Berechtigungen und andere Attribute erhalten bleiben, sodass Sie nicht dasselbe tun.
Wildcard
6

Ein paar Anmerkungen zuerst:

  • Der SSH-Server beginnt nicht mit shder Interpretation der vom Client gesendeten Befehlszeile. Er führt die Anmeldeshell des Benutzers auf dem Remote-Host als aus that-shell -c <the-string-provided-by-the-client>. Die Login-Shell des Remote-Benutzers kann alles sein. Beachten Sie, dass einige Shells mögen tcsh, fishoder rchaben sehr unterschiedliche Syntax von der sh.
  • Es ist wirklich eine Befehlszeile oder genauer eine Zeichenfolge (die Zeilenumbrüche enthalten kann, also mehrere Zeilen). Selbst wenn Sie das tun , ssh host cmd arg1 'arg 2'wo cmd, arg1und arg 2sind drei Argumente übergeben ssh, sshverkettet diese Argumente mit Leerzeichen und tatsächlich sendet die cmd arg1 arg 2Zeichenfolge an sshd, und die Remote - Shell würde , dass in Split cmd, arg1, argund 2.
  • !(subdir)ist ein Glob-Operator (ein kshGlob-Operator, der auch von zsh -o kshglobund unterstützt wird bash -O extglob). Wie bei allen Globs werden versteckte Dateien ausgeschlossen. Achten Sie daher darauf, dass möglicherweise andere Dateien ausgeschlossen sind.

Um das Problem beim Herausfinden der richtigen Syntax für die Remote-Shell zu vermeiden, können Sie dieser anderen Shell tatsächlich mitteilen, dass sie die gewünschte Shell starten und den Code über stdin eingeben soll (eine der unter Ausführen einer beliebigen einfachen Liste aufgeführten Optionen) Befehl über ssh ohne die Login-Shell des Remote-Benutzers zu kennen? )

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

bash -O extglob -O dotglobist eine Befehlszeile, die von allen wichtigen Shells, einschließlich Bourne-ähnlichen Shells, csh, rc, fish ..., gleich verstanden wird. Dies funktioniert, solange bashes installiert ist und sich im Benutzer befindet $PATH(Standard $PATH, möglicherweise vom Benutzer geändert) Login Shell wie mit ~/.zshenvfür zsh, ~/.cshrcfür csh, ~/.bashrcfür bash).

POSIXly (obwohl in der Praxis möglicherweise mehr Systeme einen bashBefehl als einen paxBefehl haben) können Sie Folgendes tun:

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

-sWendet Ersetzungen auf die übertragenen Pfade an. Wenn diese Ersetzung auf nichts erweitert wird, wird die Datei ausgeschlossen. Das Problem ist, dass Ersetzungen auch für das Ziel von Symlinks gelten. Aus diesem Grund verwenden wir .//.oben, um die Wahrscheinlichkeit zu verringern, dass ein Symlink betroffen ist.

Stéphane Chazelas
quelle
4

Ich denke nicht, dass sshes auf die Verwendung beschränkt ist sh. Es hängt vielmehr davon ab, was auf dem Zielsystem installiert ist, wie der Benutzer eingerichtet ist und welche Shells zulässig sind /etc/shells.

Hast du den chshBefehl in Betracht gezogen ?

RudiC
quelle
4

Wenn Sie es schnell machen möchten, können Sie es rsyncmit einem anderen Verschlüsselungsalgorithmus betrachten. Dies gibt Ihnen die Möglichkeit, usw. einfach auszuschließen, ohne viel Geschwindigkeit zu opfern.

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

Zusammen mit dem Hinzufügen der arcfourVerschlüsselung zu der Zeile, die mit Ciphersin beginnt /etc/ssh/ssh_config, erhalten Sie eine akzeptable Geschwindigkeit, sofern diese noch nicht aktiviert ist.

WARNUNG: Die arcfourVerschlüsselung ist unsicher . Führen Sie dies NICHT über unsichere Kanäle aus. Wenn Sie Zugriff auf den Server von unsicheren Kanälen betroffen sind arcfourVerschlüsselung, die Änderung etc/ssh/ssh_configmit einem Host-spezifischen Teil für den Quell - Host - Erstellen Sie einen HostAbschnitts in Ihrem ssh_config für Ihre Quell - Host, können Sie Ciphers arcfourdort den oben spiegeln -cSchalter, der Beschränkt die arcfourVerschlüsselung nur auf diesen Host.

Einzelheiten finden Sie in den ssh_configManpages.

Wenn Ihre CPUs jedoch den AES-NI-Befehlssatz unterstützen, wechseln Sie zu [email protected] (ja, das ist der Chiffrenname, einschließlich des @ -Stuffs), der den blitzschnellen (mit AES-NI) AES128 verwendet -GCM.

Wenn eine CPU AES-NI unterstützt, wechseln Sie "ssh -T -c arcfour -o Compression=no -x"zu, "ssh -T -c [email protected] -o Compression=no -x"um sicherere Ergebnisse zu erzielen.

Erläuterung

rsync

  • (Nicht verwenden -z, es ist viel langsamer)
  • a: Archivierungsmodus - reskursiv, behält den Besitzer, die Berechtigungen, die Änderungszeiten, die Gruppe, kopiert Symlinks als Symlinks und bewahrt Gerätedateien.
  • H: bewahrt Hardlinks
  • A: behält ACLs bei
  • X: behält erweiterte Attribute bei
  • x: Dateisystemgrenzen nicht überschreiten
  • v: Ausführlichkeit erhöhen
  • --numeric-ds: Ordnen Sie UID / GID-Werte nicht dem Benutzer- / Gruppennamen zu
  • Wenn Sie synchronisieren müssen, fügen Sie --deleteFolgendes hinzu : Löschen Sie fremde Dateien aus den Zielverzeichnissen (differenzielle Bereinigung während der Synchronisierung).
  • --progress: Fortschritt während der Übertragung anzeigen

ssh

  • T: Schalten Sie pseudo-tty aus, um die CPU-Last am Ziel zu verringern.
  • c arcfour: Verwenden Sie die schwächste, aber schnellste SSH-Verschlüsselung. Muss "siphers arcfour" in sshd_config am Ziel angeben.
  • o Compression=no: Schalten Sie die SSH-Komprimierung aus.
  • x: Deaktivieren Sie die X-Weiterleitung, wenn sie standardmäßig aktiviert ist.

Das Rindfleisch ist in den sshOptionen - wenn Sie nur rsync -avund das -e ssh -T -c arcfour -o Compression=no -x"Teil verwenden, können Sie diese Geschwindigkeiten auch erhalten.


Vergleich:

  • 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

Quellen :

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

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

emk2203
quelle
3
Nun, sie scheinen cp -rim Remote-System ausgeführt zu werden, daher ist die von der SSH-Verbindung verwendete Verschlüsselung nicht wirklich relevant. In jedem Fall arcfourwird es als ziemlich kaputt angesehen und OpenSSH deaktiviert es zusammen mit anderen auf dem Server standardmäßig seit Version 6.7 (06.10.2014) . In jedem Fall ssh -o Ciphers='aes128-ctr'gibt mir etwa 90 MB / s, was auf einer 1 Gbit / s-Verbindung schnell genug sein sollte.
Ilkkachu
Ja, arcfour ist kaputt, aber in diesem Fall sollte es keine SECURE-Shell sein, sondern eine "komfortablere Shell" ohne Schwerpunkt auf der Verschlüsselung. Ich würde dies nicht über unsichere Verbindungen verwenden, das ist richtig. Wenn 'aes128-ctr' schnell genug ist, kann und sollte es stattdessen verwendet werden.
Emk2203
Siehe auch meine erweiterte Antwort zur Verwendung mit CPUs, die AES-NI unterstützen.
Emk2203
2

Nach meinen Berechnungen verwendet die schnellste vollständige Kopie immer 'tar' (hier unter der Annahme von GNU taroder kompatibel).

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

Und tarbietet unzählige Optionen zum Bearbeiten von Attributen, Berechtigungen und zum Auswählen / Ausschließen von Dateien. Mit dem obigen Befehl wird beispielsweise der Unterordner der obersten Ebene mit dem Namen .thumbcache beim Kopieren ausgeschlossen.

Lam Das
quelle
Beachten Sie, dass --exclude=.thumbcacheumfasst nicht alle die .thumbcacheDateien, nicht nur die eine auf der obersten Ebene. Mit GNU tar(nicht bsdtar) können Sie --exclude=./.thumbcachenur die .thumbcacheDatei der obersten Ebene ausschließen .
Stéphane Chazelas