Estoy tratando de copiar archivos a través de SSH , pero no puedo usarlos scpporque no conozco el nombre de archivo exacto que necesito. Aunque los archivos binarios pequeños y los archivos de texto se transfieren bien, los archivos binarios grandes se alteran. Aquí está el archivo en el servidor:
remote$ ls -la
-rw-rw-r-- 1 user user 244970907 Aug 24 11:11 foo.gz
remote$ md5sum foo.gz
9b5a44dad9d129bab52cbc6d806e7fda foo.gz
Aquí está el archivo después de moverlo:
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
¡Tenga en cuenta que el archivo descargado es más grande que el del servidor! Sin embargo, si hago lo mismo con un archivo muy pequeño, entonces todo funciona como se esperaba:
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
usuario real 0m3.041s 0m0.013s sys 0m0.005s
local$ md5sum hi.txt.gz
08bf5080733d46a47d339520176b9211 hi.txt.gz
Ambos tamaños de archivo son 26 bytes en este caso.
¿Por qué los archivos pequeños pueden transferirse bien, pero los archivos grandes obtienen algunos bytes?

-topción, que rompe la transferencia. No use-to-T, a menos que los necesite por una razón muy específica. El valor predeterminado funciona en la gran mayoría de los casos, por lo que esas opciones rara vez se necesitan.ssh -t cates la única forma de transferir archivos.Respuestas:
TL; DR
No utilice
-t.-timplica un pseudo-terminal en el host remoto y solo debe usarse para ejecutar aplicaciones visuales desde un terminal.Explicación
El carácter de salto de línea (también conocido como nueva línea o
\n) es el que cuando se envía a un terminal le dice al terminal que mueva el cursor hacia abajo.Sin embargo, cuando se ejecuta
seq 3en una terminal, ahí es dondeseqescribe1\n2\n3\nalgo así/dev/pts/0, no ve:pero
¿Porqué es eso?
En realidad, cuando
seq 3(ossh host seq 3para el caso) escribe1\n2\n3\n, el terminal ve1\r\n2\r\n3\r\n. Es decir, los avances de línea se han traducido en retorno de carro (sobre el cual los terminales mueven su cursor hacia la izquierda de la pantalla) y avance de línea.Eso lo hace el controlador del dispositivo terminal. Más exactamente, por la disciplina de línea del dispositivo terminal (o pseudo-terminal), un módulo de software que reside en el núcleo.
Puede controlar el comportamiento de esa disciplina de línea con el
sttycomando. La traducción deLF->CRLFse activa con(que generalmente está habilitado de forma predeterminada). Puedes apagarlo con:
O puede desactivar todo el procesamiento de salida con:
Si haces eso y corres
seq 3, verás:como se esperaba.
Ahora, cuando lo haces:
seqya no está escribiendo en un terminal, está escribiendo en un archivo, no se está haciendo ninguna traducción. Entoncessome-filecontiene1\n2\n3\n. La traducción solo se realiza cuando se escribe en un dispositivo terminal. Y solo se hace para mostrar.de manera similar, cuando haces:
sshestá escribiendo1\n2\n3\nindependientemente de a qué sesshdirige la salida.Lo que realmente sucede es que el
seq 3comando se ejecutahostcon su stdout redirigido a una tubería. Elsshservidor en el host lee el otro extremo de la tubería y lo envía a través del canal encriptado a susshcliente y elsshcliente lo escribe en su stdout, en su caso, un dispositivo pseudo-terminal, dondeLFse traducenCRLFpara su visualización.Muchas aplicaciones interactivas se comportan de manera diferente cuando su stdout no es un terminal. Por ejemplo, si ejecutas:
vino le gusta, no le gusta que su salida vaya a una tubería. Cree, por ejemplo, que no está hablando con un dispositivo que puede entender las secuencias de escape de posicionamiento del cursor.Entonces
sshtiene la-topción para eso. Con esa opción, el servidor ssh en el host crea un dispositivo pseudo-terminal y lo convierte en stdout (y stdin y stderr) devi. Lo queviescribe en ese dispositivo terminal pasa por esa disciplina remota de línea pseudo-terminal y es leída por elsshservidor y enviada por el canal encriptado alsshcliente. Es lo mismo que antes, excepto que en lugar de usar una tubería , elsshservidor usa un pseudo-terminal .La otra diferencia es que en el lado del
sshcliente , el cliente establece el terminal enrawmodo. Eso significa que no se realiza ninguna traducción allí (opostestá deshabilitado y también otros comportamientos del lado de entrada). Por ejemplo, cuando escribe Ctrl-C, en lugar de interrumpirssh, ese^Ccarácter se envía al lado remoto, donde la disciplina de línea del pseudo terminal remoto envía la interrupción al comando remoto.Cuando tu lo hagas:
seq 3escribe1\n2\n3\nen su stdout, que es un dispositivo pseudo-terminal. Debido aonlcrque se traduce en el host para1\r\n2\r\n3\r\nenviar a usted a través del canal cifrado. Por su parte, no hay traducción (onlcrdeshabilitada), por lo que1\r\n2\r\n3\r\nse muestra intacta (debido alrawmodo) y correctamente en la pantalla de su emulador de terminal.Ahora, si lo haces:
No hay diferencia desde arriba.
sshescribirá lo mismo:1\r\n2\r\n3\r\npero esta vez ensome-file.Así que, básicamente, todo el
LFen la salida deseqhaber sido traducida aCRLFdentrosome-file.Es lo mismo si haces:
Todos los
LFcaracteres (0x0a bytes) se están traduciendo a CRLF (0x0d 0x0a).Esa es probablemente la razón de la corrupción en su archivo. En el caso del segundo archivo más pequeño, sucede que el archivo no contiene 0x0a bytes, por lo que no hay corrupción.
Tenga en cuenta que podría obtener diferentes tipos de corrupción con diferentes configuraciones de tty. Otro tipo potencial de corrupción asociada
-tes si sus archivos de inicio enhost(~/.bashrc,~/.ssh/rc...) escriben cosas en su stderr, porque con-tstdout y stderr del shell remoto terminan fusionándose ensshstdout (ambos van al pseudo -dispositivo terminal).No desea que el control remoto se
catenvíe a un dispositivo terminal allí.Usted quiere:
Podrías hacerlo:
Eso funcionaría (excepto en el caso de corrupción escrito por stderr discutido anteriormente), pero incluso eso sería subóptimo, ya que tendría esa capa pseudo-terminal innecesaria ejecutándose
host.Un poco más divertido:
OKAY.
LFtraducido aCRLFOK otra vez
Esa es otra forma de procesamiento posterior de salida que puede realizar la disciplina de línea terminal.
sshse niega a decirle al servidor que use un pseudo terminal cuando su propia entrada no es un terminal. Sin embargo, puedes forzarlo con-tt:La disciplina de línea hace mucho más en el lado de entrada.
Aquí,
echono lee su entrada ni se le pide que la envíe,x\r\n\nentonces, ¿de dónde viene? Ese es el localechodel pseudo-terminal remoto (stty echo). Elsshservidor está enviando lax\nlectura del cliente al lado maestro del pseudo terminal remoto. Y la disciplina de línea de eso se repite (antesstty opostse ejecuta, por eso vemos aCRLFy noLF). Eso es independiente de si la aplicación remota lee algo de stdin o no.El
0x3carácter se repite como^C(^yC) debido astty echoctly el shell y el sueño reciben un SIGINT porquestty isig.Entonces mientras:
es bastante malo, pero
transferir archivos al revés es mucho peor. Usted obtendrá algunos CR -> Traducción LF, sino también problemas con todos los caracteres especiales (
^C,^Z,^D,^?,^S...) y también el control remotocatno verá EF cuando el fin delocal-fileque se alcance, sólo cuando^Dse envía después de una\r,\nu otro^Dcomo cuando lo hacescat > fileen tu terminal.fuente
Cuando se usa ese método para copiar el archivo, los archivos parecen ser diferentes.
Servidor remoto
Servidor local
Ejecutando su
ssh ... catcomando:Resultados en este archivo en el servidor local:
¿Investigando por qué?
Investigar el archivo resultante en el lado local muestra que ha sido dañado. Si quita el
-tinterruptor de susshcomando, entonces funciona como se esperaba.Las sumas de verificación ahora también funcionan:
fuente