今まで余り考えずクライアント側のコマンドをただ実行するだけで知らなかったのだが、scpには-t-fというオプションがあるらしい。 このオプション付きでサーバ側でscpを実行することで、標準入力から処理内容を受け付けてファイルを転送しているそうだ。

1. ローカルからリモートへ転送する場合

ローカルからリモートに転送する場合は、以下のように改行区切りで指示を出し、それをパイプでscpに渡す。 転送する対象となるファイルPATHやサイズを指定して、次にその中身を出力している。1ファイルにつき1回づつ転送することになるようで、配下のディレクトリを指定したら自動で作成されるようだ。

bash
{ echo D0755 0 test_dir3; echo C0644 12 test1; printf 'hello\ntest1\n'; printf \\000; } | scp -rt /tmp
shell
blacknon@test-ubuntu:~$ { echo D0755 0 test_dir3; echo C0644 12 test1; printf 'hello\ntest1\n'; printf \\000; } D0755 0 test_dir3 C0644 12 test1 hello test1 blacknon@test-ubuntu:~$ { echo D0755 0 test_dir3; echo C0644 12 test1; printf 'hello\ntest1\n'; printf \\000; } | scp -rt /tmp test1 100% 12 0.0KB/s 00:00 blacknon@test-ubuntu:~$ ls -al /tmp/test_dir3/ 合計 12 drwxr-xr-x 2 blacknon blacknon 4096 5月 6 00:42 . drwxrwxrwt 15 root root 4096 5月 6 00:42 .. -rw-r--r-- 1 blacknon blacknon 12 5月 6 00:42 test1 blacknon@test-ubuntu:~$ cat /tmp/test_dir3/test1 hello test1

複数ファイルを送信する場合、Nullキャラクタで区切った後に送信内容(ファイル名、サイズ、中身)を送信しているようだ。

bash
{ echo D0755 0 test_dir3; \ echo C0644 12 test1; \ printf 'hello\ntest1\n'; \ printf \\000; \ echo C0644 12 test2; \ printf 'hello\ntest2\n'; \ printf \\000; } | scp -rt /tmp
shell
blacknon@test-ubuntu:~$ { echo D0755 0 test_dir3; \ > echo C0644 12 test1; \ > printf 'hello\ntest1\n'; \ > printf \\000; \ > echo C0644 12 test2; \ > printf 'hello\ntest2\n'; \ > printf \\000; } | scp -rt /tmp test1 100% 12 0.0KB/s 00:00 test2 100% 12 0.0KB/s 00:00 blacknon@test-ubuntu:~$ ls -al /tmp/test_dir3/ 合計 16 drwxr-xr-x 2 blacknon blacknon 4096 5月 6 00:53 . drwxrwxrwt 15 root root 4096 5月 6 00:54 .. -rw-r--r-- 1 blacknon blacknon 12 5月 6 00:53 test1 -rw-r--r-- 1 blacknon blacknon 12 5月 6 00:53 test2 blacknon@test-ubuntu:~$ grep '' /tmp/test_dir3/* /tmp/test_dir3/test1:hello /tmp/test_dir3/test1:test1 /tmp/test_dir3/test2:hello /tmp/test_dir3/test2:test2

2. リモートからローカルへ転送する場合

リモートからローカルに転送する際、ローカル側からはNullキャラクタを(最低でも)7個渡すことで、指定したディレクトリ配下やファイルの内容を取得するようだ。ここで渡すNullキャラクタの個数だけ、scpから情報を取得できる(ファイルの中身は何行あってもNullキャラクタ1個分)。 (ちなみに、以下の例ではNullキャラクタが分かるよう、cat -Aに繋いでいる)

bash
printf \\000\\000\\000\\000\\000\\000\\000 | scp -rf /tmp/test_dir3
shell
blacknon@test-ubuntu:~$ printf \\000\\000\\000\\000\\000\\000\\000 | scp -rf /tmp/test_dir3 | cat -A D0755 0 test_dir3$ C0644 12 test1$ hello$ test1$ ^@C0644 12 test2$ hello$ test2$ ^@E$

あとは、出力された内容を受け付けてファイルに書き出せばいい。 これをそのままscp -tで受け付けてもそのままファイルに書き出してくれる。


参考