リモートホストとの間でファイルやディレクトリを転送(送信・受信)したいんだけど、何らかの事情でscpやsftpが使えない(or 使いたくない)からsshだけでなんとかしたい、という時の方法。
まずは結論から
送信
ローカルホストにあるファイル source_dir/source_file
をリモートホストの destination_dir
に転送するには:
tar czf - -C source_dir source_file | ssh user@remote-host 'tar zxvf - -C destination_dir'
とします。source_file
はファイルでもディレクトリでも大丈夫です(ディレクトリなら再帰的に転送されます)。
受信
リモートホストにあるファイル source_dir/source_file
をローカルの destination_dir
に転送するには:
ssh user@remote-host 'tar czf - -C source_dir source_file' | tar zxvf - -C destination_dir
とします。source_file
はファイルでもディレクトリでも大丈夫です(ディレクトリなら再帰的に転送されます)。
解説
ssh
コマンドはホスト名の後に引数を与えると、通常の動作と異なり、リモートホスト上でその引数をコマンドとして実行して終了します。
その際、ローカルホストとの間でパイプをつなげることができます。
つまり、ローカルホストのコマンドの標準出力をリモートホストのコマンドの標準入力で受け取ったり、
リモートホストのコマンドの標準出力をローカルホストのコマンドの標準入力で受け取ったりできます。
さて、あるディレクトリ以下のファイルを再帰的にコピーするのに tar
を利用する方法があります。
使用頻度は少ないものの、小さいファイルが大量にある場合には cp -r
を使うより速かったりします。こんな具合ですね。
tar cf - -C source_dir source_file | tar xvf - -C destination_dir
アーカイブを生成して標準出力に書き出し、標準入力で受け取って別ディレクトリで展開しています。
そう、結論で書いたのは、この方法をリモートホストとの間でやっているだけです。
ついでに、ネットワークを経由しますので tar
コマンドにgzip圧縮のオプション z
を加えています。
ちなみに、パイプで繋げられるなら tar
じゃなくても大丈夫じゃないか?と思われた方、その通りです。
例えば、単一のファイルなら cat
でも転送を実現できます。送信なら
cat source_dir/source_file | ssh user@remote-host 'cat > destination_dir/destination_file'
ですね。ネットワーク帯域の消費を節約するためgzip圧縮したいなら、
gzip -c source_dir/source_file | ssh user@remote-host 'gunzip > destination_dir/destination_file'
としてもいいでしょう。
他にもいろいろ応用が効くと思います。tarのオプションを工夫すれば特定ファイルの除外なども可能ですね。
参考