頑張ってるSSH経由でファイルをコピーするscp
しかし、必要な正確なファイル名がわからないので動作しません。小さなバイナリとテキストファイルはうまく転送されますが、大きなバイナリファイルは変更されます。以下はサーバー上のファイルです。
remote$ ls -la
-rw-rw-r-- 1 user user 244970907 Aug 24 11:11 foo.gz
remote$ md5sum foo.gz
9b5a44dad9d129bab52cbc6d806e7fda foo.gz
ファイルを移動した後のファイルは次のとおりです。
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
ダウンロードしたファイルは次のとおりです。大きいサーバーよりもいいですね!しかし、非常に小さなファイルで同じことを行うと、すべてが期待どおりに機能します。
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
実際の0m3.041sユーザー0m0.013sシステム0m0.005s
local$ md5sum hi.txt.gz
08bf5080733d46a47d339520176b9211 hi.txt.gz
この例では、両方のファイルのサイズは26バイトです。
小さなファイルはうまく転送されますが、大きなファイルはいくつかのバイトを追加するのですか?
答え1
長い話を短く
を使用しないでください-t
。-t
リモートホストの擬似端末に関連しており、端末でビジュアルアプリケーションを実行するためにのみ使用する必要があります。
説明する
改行文字(newlineまたはnewlineとも呼ばれます\n
)は、端末に送信されたときに端末にカーソルを下に移動するように指示する文字です。
seq 3
ただし、端末で実行している場合、つまり次のようにseq
書くと、次のものは表示されません。1\n2\n3\n
/dev/pts/0
1
2
3
しかし、
1
2
3
なぜそんなことですか?
実際に書き込むとseq 3
(またはssh host seq 3
その問題について)、1\n2\n3\n
端末はを見ます1\r\n2\r\n3\r\n
。つまり、改行文字はキャリッジリターン文字(この時点で端末がカーソルを画面の左側に戻す)と改行文字に変換されます。
これは、端末装置ドライバによって行われる。より正確には、端末(または疑似端末)デバイスの接続規則に従ってカーネルに常駐するソフトウェアモジュールです。
コマンドを使用して、この線規則の動作を制御できますstty
。LF
->翻訳CRLF
を通過
stty onlcr
(通常はデフォルトで有効になっています)。次の方法でドラッグできます。
stty -onlcr
または、以下を使用してすべての出力処理をオフにすることができます。
stty -opost
これを実行して実行すると、seq 3
次のようになります。
$ stty -onlcr; seq 3
1
2
3
予想通り。
今これを行う:
seq 3 > some-file
seq
端末デバイスに書き込むのではなく、変換なしで通常のファイルに書き込みます。some-file
包容も同じだ1\n2\n3\n
。変換は、端末装置に書き込む場合にのみ発生します。そしてこれはただ見せることです。
同様に、次のことを行うとき:
ssh host seq 3
ssh
出力は何でも1\n2\n3\n
関係なく作成されます。ssh
実際に起こるのは、seq 3
コマンドが実行されるとhost
stdoutがパイプにリダイレクトされることです。ssh
ホストのサーバーはパイプのもう一方の端を読み取り、それを暗号化されたチャネルを介してクライアントに送信しますssh
。クライアントssh
はこれをstdout(あなたの場合は疑似端末デバイス)に書き込むことで、LF
sがCRLF
表示されるように変換されます。
多くのインタラクティブなアプリケーションは、標準出力が端末でない場合、異なる動作をします。たとえば、次を実行する場合:
ssh host vi
vi
それは気に入らず、出力がパイプに入るのが好きではありません。たとえば、カーソル位置決めエスケープシーケンスを理解するデバイスと通信しないとします。
だからそのオプションがssh
あります-t
。このオプションを有効にすると、ホスト上のSSHサーバーは疑似端末装置を作成し、それを疑似端末装置として使用しますvi
。端末装置に記録されたコンテンツは、vi
リモート擬似端末回線規則を経てサーバーから読み取られ、暗号化されたチャネルを介しssh
てssh
管路、ssh
サーバーは擬似端末。
別の違いは、クライアント側でssh
クライアントが端末をraw
モードに設定し、ローカルを無効にすることです。エコ)。これは翻訳が行われないことを意味します(opost
無効化および他の入力側の動作)。たとえば、入力するとその文字がリモートエンドに送信され、Ctrl-C中断するのではなくリモート疑似端末の行ルールが実行されます。ssh
^C
邪魔するリモートコマンドで。
これを行うとき:
ssh -t host seq 3
seq 3
1\n2\n3\n
擬似端末装置である標準出力に書き込みます。onlcr
翻訳されたからホストから1\r\n2\r\n3\r\n
暗号化されたチャンネルを介してあなたに送信されます。あなたの側に翻訳がないので(onlcr
無効)1\r\n2\r\n3\r\n
、変更せず(モードによって)、端末エミュレータ画面に正しく表示されます。raw
今これを行う:
ssh -t host seq 3 > some-file
上記と違いはありません。ssh
同じことを書くでしょう: 1\r\n2\r\n3\r\n
、しかし今回はsome-file
。
したがって、基本的にすべてのLF
出力seq
は。CRLF
some-file
これにより結果は同じになります。
ssh -t host cat remote-file > local-file
すべてのLF
文字(0x0aバイト)はCRLF(0x0d 0x0a)に変換されます。
これがファイルが破損した理由かもしれません。 2番目の小さなファイルでは、ファイルに0x0aバイトが含まれていないため、破損はありません。
異なる tty 設定により、他の種類の損傷が発生する可能性があります。これに関連する別の潜在的な破損の種類は、(-t
、...)の起動ファイルがstderrに何かを書き込む場合です。これは、リモートシェルのstdoutとstderrが最終的にstdoutにマージされるためです(どちらも擬似端末デバイスに移動します)。host
~/.bashrc
~/.ssh/rc
-t
ssh
cat
リモコン出力をエンドデバイスに転送したくありません。
あなたが望むもの:
ssh host cat remote-file > local-file
次のことができます。
ssh -t host 'stty -opost; cat remote-file' > local-file
これでうまくいきます(次の場合は除く)。標準エラーに書き込む上記で議論したダメージ)、しかしこれも最適ではありませんhost
。
もっと面白いものがあります:
$ ssh localhost echo | od -tx1
0000000 0a
0000001
いいね
$ ssh -t localhost echo | od -tx1
0000000 0d 0a
0000002
LF
翻訳するCRLF
$ ssh -t localhost 'stty -opost; echo' | od -tx1
0000000 0a
0000001
もう一度知りました。
$ ssh -t localhost 'stty olcuc; echo x'
X
これは、ターミナルラインルールを介して実行できる出力後処理の別の形式です。
$ echo x | ssh -t localhost 'stty -opost; echo' | od -tx1
Pseudo-terminal will not be allocated because stdin is not a terminal.
stty: standard input: Inappropriate ioctl for device
0000000 0a
0000001
ssh
Reject は、サーバー自体の入力が端末でない場合に擬似端末を使用するようサーバーに指示します。-tt
しかし、強制的に適用することはできます。
$ echo x | ssh -tt localhost 'stty -opost; echo' | od -tx1
0000000 x \r \n \n
0000004
ライン規律は、入力側でより多くのタスクを実行します。
ここでは、echo
入力を読み取らずに出力するように要求しません。x\r\n\n
それでは、その入力はどこから来るのでしょうか?これはecho
リモート疑似端末()のローカル端末ですstty echo
。サーバーは、クライアントから読み取られたデータをリモート疑似端末のホストにssh
送信します。x\n
その行ルールはこれを反映しています(beforestty opost
がrunなので、CRLF
代わりにaが表示されますLF
)。リモートアプリケーションがstdinから何でも読み取るかどうかは問題ではありません。
$ (sleep 1; printf '\03') | ssh -tt localhost 'trap "echo ouch" INT; sleep 2'
^Couch
なぜなら、この文字は0x3
(and)でエコーされ、シェルとスリープはSIGINTを受け取るからです。^C
^
C
stty echoctl
stty isig
だから同時に:
ssh -t host cat remote-file > local-file
十分悪いけど、
ssh -tt host 'cat > remote-file' < local-file
ファイルを反対方向に転送する方がはるかに悪いです。 CR - > LF変換が行われますが、すべての特殊文字(^C
、、、、、... )にも問題があり、eofの終わりに達すると、リモートデバイスは次の場合にのみeof^Z
を表示できます。端末で行うのと同様の操作の後に送信します。^D
^?
^S
cat
local-file
^D
\r
\n
^D
cat > file
答え2
この方法を使用してファイルをコピーすると、ファイルが異なるように見えます。
リモートサーバー
ls -l | grep vim_cfg
-rw-rw-r--. 1 slm slm 9783257 Aug 5 16:51 vim_cfg.tgz
ローカルサーバー
次のコマンドを実行してくださいssh ... cat
。
$ ssh dufresne -t 'cat ~/vim_cfg.tgz' > vim_cfg.tgz
ローカルサーバーでこのファイルを生成した結果:
$ ls -l | grep vim_cfg.tgz
-rw-rw-r--. 1 saml saml 9820481 Aug 24 12:13 vim_cfg.tgz
原因を調べてみましょうか?
生成されたファイルをローカルで調べたところ、破損していることがわかりました。コマンドから-t
スイッチを取り出すと、期待どおりに動作します。ssh
$ ssh dufresne 'cat ~/vim_cfg.tgz' > vim_cfg.tgz
$ ls -l | grep vim_cfg.tgz
-rw-rw-r--. 1 saml saml 9783257 Aug 24 12:17 vim_cfg.tgz
これでチェックサムも動作します。
# remote server
$ ssh dufresne "md5sum ~/vim_cfg.tgz"
9e70b036836dfdf2871e76b3636a72c6 /home/slm/vim_cfg.tgz
# local server
$ md5sum vim_cfg.tgz
9e70b036836dfdf2871e76b3636a72c6 vim_cfg.tgz