scpで複数ファイルをダウンロードするときの小さな落とし穴


TL;DR

scpで、リモートのファイル名をワイルドカード展開やブレース展開するときはエスケープしよう

本題

リモートサーバーのディレクトリ構成
/home/
└── user/
    ├── file1
    ├── file2
    └── fileA

このようなリモートサーバーから、ローカルのカレントディレクトリにファイルをダウンロードしたい。

file1のみダウンロード

scp user@remote:/home/user/file1 .

うん、問題ないですね。

file1, file2, fileAをダウンロード

scp user@remote:/home/user/file* .

ワイルドカード展開も使える。

file1, fileAをダウンロード

scp user@remote:/home/user/file{1,A} .

ワイルドカードが使えればブレース展開も使えるはずですね。
実際このコマンドも上手く動きます。

パスワードを2回求められることを除いては!

なぜ?

先ほどのコマンドは、以下と同じです。

scp user@remote:/home/user/file1 user@remote:/home/user/fileA .

これがもし、1つ目の引数と2つ目とで違うリモートサーバーだとしたら、パスワードを2回入力するのも納得でしょう。
各リモートアドレスが同じかどうかまで、scpは面倒見てくれません。

解決策

シェルがブレース展開するからいけないのです。
scpに展開させましょう。

scp user@remote:/home/user/file\{1,A} .

ブレースをエスケープしただけですが、これでシェルではなくscp側で展開してくれるので、パスワード1回で済みます。

ちなみにワイルドカード展開も、たまたまローカルマシンにuser@remote:/home/user/file*にマッチするファイルがなかっただけです。

マッチしなければ基本的にそのまま引数に渡してくれるはずですが、これもエスケープしておいたほうが安全でしょう。