Ich versuche, Dateien über SSH zu kopieren , kann sie jedoch nicht verwenden scp
, da ich den genauen Dateinamen nicht kenne. Obwohl kleine Binärdateien und Textdateien problemlos übertragen werden, werden große Binärdateien geändert. Hier ist die Datei auf dem Server:
remote$ ls -la
-rw-rw-r-- 1 user user 244970907 Aug 24 11:11 foo.gz
remote$ md5sum foo.gz
9b5a44dad9d129bab52cbc6d806e7fda foo.gz
Hier ist die Datei, nachdem ich sie verschoben habe:
local$ time ssh [email protected] -t 'cat /path/to/foo.gz' > latest.gz
real 1m52.098s
user 0m2.608s
sys 0m4.370s
local$ md5sum latest.gz
76fae9d6a4711bad1560092b539d034b latest.gz
local$ ls -la
-rw-rw-r-- 1 dotancohen dotancohen 245849912 Aug 24 18:26 latest.gz
Beachten Sie, dass die heruntergeladene Datei größer ist als die auf dem Server! Wenn ich jedoch mit einer sehr kleinen Datei dasselbe mache, funktioniert alles wie erwartet:
remote$ echo "Hello" | gzip -c > hello.txt.gz
remote$ md5sum hello.txt.gz
08bf5080733d46a47d339520176b9211 hello.txt.gz
local$ time ssh [email protected] -t 'cat /path/to/hello.txt.gz' > hi.txt.gz
echte 0m3.041s Benutzer 0m0.013s sys 0m0.005s
local$ md5sum hi.txt.gz
08bf5080733d46a47d339520176b9211 hi.txt.gz
Beide Dateigrößen betragen in diesem Fall 26 Byte.
Warum können kleine Dateien problemlos übertragen werden, aber große Dateien werden mit einigen Bytes versehen?
-t
Option, die die Übertragung unterbricht. Verwenden Sie nicht-t
oder-T
, es sei denn, Sie benötigen sie aus einem bestimmten Grund. Die Standardeinstellung funktioniert in den allermeisten Fällen, sodass diese Optionen sehr selten benötigt werden.ssh -t cat
die einzige Möglichkeit ist, Dateien zu übertragen.Antworten:
TL; DR
Nicht verwenden
-t
.-t
beinhaltet ein Pseudoterminal auf dem Remote-Host und sollte nur zum Ausführen visueller Anwendungen von einem Terminal aus verwendet werden.Erläuterung
Das Zeilenvorschubzeichen (auch als Zeilenvorschub oder als "Zeilenvorschub" bezeichnet
\n
) weist das Terminal an, den Cursor nach unten zu bewegen, wenn es an ein Terminal gesendet wird.Wenn Sie jedoch
seq 3
in einem Terminal ausgeführt werden und dort auf etwasseq
schreiben , sehen Sie nicht:1\n2\n3\n
/dev/pts/0
aber
Warum das?
Tatsächlich sieht das Terminal , wenn
seq 3
(oderssh host seq 3
in diesem Fall) schreibt . Das heißt, die Zeilenvorschübe wurden in Wagenrücklauf (auf den Terminals den Cursor zurück nach links bewegen) und Zeilenvorschub übersetzt.1\n2\n3\n
1\r\n2\r\n3\r\n
Das erledigt der Endgerätetreiber. Genauer gesagt, nach der Leitungsdisziplin des Endgeräts (oder Pseudo-Endgeräts) ein Softwaremodul, das sich im Kernel befindet.
Sie können das Verhalten dieser Zeilendisziplin mit dem
stty
Befehl steuern . Die Übersetzung vonLF
->CRLF
wird mit eingeschaltet(die in der Regel standardmäßig aktiviert ist). Sie können es ausschalten mit:
Oder Sie können die gesamte Ausgabeverarbeitung ausschalten mit:
Wenn du das tust und rennst
seq 3
, siehst du:wie erwartet.
Nun, wenn Sie dies tun:
seq
schreibt nicht mehr in ein Terminal, es wird in eine Datei geschrieben, es wird keine Übersetzung durchgeführt. Enthältsome-file
also1\n2\n3\n
. Die Übersetzung erfolgt nur beim Schreiben auf ein Endgerät. Und es ist nur für die Anzeige gemacht.in ähnlicher Weise, wenn Sie tun:
ssh
schreibt,1\n2\n3\n
unabhängig davonssh
, wohin die Ausgabe geht.Was tatsächlich passiert, ist, dass der
seq 3
Befehlhost
mit seiner stdout ausgeführt wird, die an eine Pipe umgeleitet wird. Derssh
Server auf dem Host liest das andere Ende der Pipe und sendet es über den verschlüsselten Kanal an Ihrenssh
Client. Derssh
Client schreibt es auf seinen Standardausgang, in Ihrem Fall ein Pseudo-Endgerät, in dasLF
sCRLF
zur Anzeige übersetzt werden.Viele interaktive Anwendungen verhalten sich anders, wenn ihre Standardausgabe kein Terminal ist. Wenn Sie beispielsweise Folgendes ausführen:
vi
mag es nicht, mag es nicht, wenn seine Ausgabe an eine Pipe geht. Es spricht nicht mit einem Gerät, das zum Beispiel die Escape-Sequenzen für die Cursorpositionierung versteht.Also
ssh
hat die-t
Option dafür. Mit dieser Option erstellt der ssh-Server auf dem Host ein Pseudo-Terminal-Gerät und erstellt das stdout (und stdin und stderr) vonvi
. Wasvi
auf diesem Endgerät schreibt, durchläuft diese Pseudo-Terminal-Leitungsdisziplin und wird vomssh
Server gelesen und über den verschlüsselten Kanal an denssh
Client gesendet . Es ist das gleiche wie zuvor , außer daß anstelle der Verwendung eines Rohres , dasssh
verwendet Server ein Pseudo-Terminal .Der andere Unterschied besteht darin, dass der Client auf der
ssh
Clientseite das Terminal in denraw
Modus versetzt. Das bedeutet, dass dort keine Übersetzung durchgeführt wird (opost
ist deaktiviert und auch andere eingabeseitige Verhaltensweisen). Wenn Sie beispielsweise ein Zeichen Ctrl-Ceingebenssh
, wird dieses^C
Zeichen nicht unterbrochen, sondern an die entfernte Seite gesendet, wo die Leitungsdisziplin des entfernten Pseudoterminals den Interrupt an den entfernten Befehl sendet .Wenn Sie das tun:
seq 3
schreibt1\n2\n3\n
auf sein stdout, das ein Pseudo-Terminal-Gerät ist. Wegenonlcr
, die übersetzt wird auf dem Host zu1\r\n2\r\n3\r\n
und an Sie über den verschlüsselten Kanal. Auf Ihrer Seite gibt es keine Übersetzung (onlcr
deaktiviert), daher1\r\n2\r\n3\r\n
wird diese (aufgrund desraw
Modus) unangetastet und korrekt auf dem Bildschirm Ihres Terminalemulators angezeigt.Nun, wenn Sie dies tun:
Es gibt keinen Unterschied von oben.
ssh
werde das selbe schreiben:,1\r\n2\r\n3\r\n
aber diesmal insome-file
.Also im Grunde alle
LF
in der Ausgabeseq
hat übersetztCRLF
insome-file
.Es ist das gleiche, wenn Sie tun:
Alle
LF
Zeichen (0x0a Bytes) werden in CRLF (0x0d 0x0a) übersetzt.Das ist wahrscheinlich der Grund für die Beschädigung in Ihrer Datei. Im Fall der zweiten kleineren Datei kommt es einfach so vor, dass die Datei keine 0x0a-Bytes enthält, sodass keine Beschädigung vorliegt.
Beachten Sie, dass Sie mit unterschiedlichen Einstellungen für tty verschiedene Arten von Beschädigungen erhalten können. Eine weitere mögliche Art der Beschädigung
-t
besteht darin, dass Ihre Startdateien aufhost
(~/.bashrc
,~/.ssh/rc
...) Dinge in ihre stderr schreiben, da-t
stdout und stderr der Remote-Shell inssh
stdout zusammengeführt werden (beide gehen ins Pseudo Endgerät).Die Fernbedienung
cat
soll dort nicht auf ein Endgerät ausgegeben werden.Sie wollen:
Du könntest es tun:
Das würde funktionieren (außer in dem oben diskutierten Fall der Korruption beim Schreiben an stderr ), aber selbst das wäre suboptimal, da Sie diese unnötige Pseudo-Terminal-Schicht hätten
host
.Noch mehr Spaß:
OKAY.
LF
übersetzt nachCRLF
Wieder ok.
Dies ist eine andere Form der Ausgabe-Nachbearbeitung, die von der Terminalleitungsdisziplin durchgeführt werden kann.
ssh
Weigert sich, dem Server die Verwendung eines Pseudoterminals mitzuteilen, wenn seine eigene Eingabe kein Terminal ist. Du kannst es erzwingen mit-tt
:Die Liniendisziplin leistet viel mehr auf der Eingabeseite.
Hier
echo
wird weder die Eingabe gelesen noch aufgefordert, diese auszugeben.x\r\n\n
Wo kommt das her? Das ist das lokaleecho
des entfernten Pseudoterminals (stty echo
). Derssh
Server leitet denx\n
vom Client gelesenen Wert an die Masterseite des entfernten Pseudoterminals weiter. Und die Liniendisziplin von diesem spiegelt es wieder (bevorstty opost
ausgeführt wird, weshalb wir einCRLF
und nicht sehenLF
). Das ist unabhängig davon, ob die Remote-Anwendung etwas von stdin liest oder nicht.Das
0x3
Zeichen wird als^C
(^
undC
) zurückgemeldet,stty echoctl
und die Shell und der Schlaf erhalten ein ZEICHEN, weilstty isig
.Also, während:
ist schon schlimm genug, aber
Dateien in die andere Richtung zu übertragen ist viel schlimmer. Sie werden einige CR bekommen -> LF Übersetzung, aber auch Probleme mit allen Sonderzeichen (
^C
,^Z
,^D
,^?
,^S
...) und auch die Fernbedienungcat
nicht EOF sehen , wenn das Endelocal-file
erreicht ist, nur dann , wenn^D
nach einem gesendet wird\r
,\n
oder ein anderes^D
wiecat > file
in Ihrem Terminal.quelle
Wenn Sie diese Methode zum Kopieren der Datei verwenden, scheinen die Dateien unterschiedlich zu sein.
Remote-Server
Lokaler Server
Führen Sie Ihren
ssh ... cat
Befehl aus:Ergebnisse in dieser Datei auf dem lokalen Server:
Warum untersuchen?
Die Untersuchung der resultierenden Datei auf der lokalen Seite zeigt, dass sie beschädigt ist. Wenn Sie den
-t
Schalter aus Ihremssh
Befehl entfernen, funktioniert er wie erwartet.Checksummen funktionieren jetzt auch:
quelle