sshだけでファイル・ディレクトリ転送(scp, sftpなし)

  • 51
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

リモートホストとの間でファイルやディレクトリを転送(送信・受信)したいんだけど、何らかの事情で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のオプションを工夫すれば特定ファイルの除外なども可能ですね。

参考

https://meinit.nl/using-tar-and-ssh-to-efficiently-copy-files-preserving-permissions