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 user@remote:/home/user/file\{1,A} .
ブレースをエスケープしただけですが、これでローカルのシェルではなくリモートサーバ側で展開してくれるので、パスワード1回で済みます。
ちなみにワイルドカード展開も、たまたまローカルマシンにuser@remote:/home/user/file*
にマッチするファイルがなかっただけです。
~~マッチしなければ基本的にそのまま引数に渡してくれるはずですが、~~これもエスケープしておいたほうが安全でしょう。
追記:シェルのglobの挙動
ワイルドカード*
にマッチするファイルがない場合の挙動は、厳密には環境によります。
bash のデフォルト設定なら、上記のようにマッチしなければ*
を含んだ文字列をそのままコマンドに渡しますが、shopt
でnullglob
やfailglob
が設定されている場合は、引数がなくなったりエラーを吐いたりします。
さらに、zshだとエラーになるのがデフォルトです。
このあたりの挙動は以下の記事に詳しく書かれています。