17
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2018-11-22

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 のデフォルト設定なら、上記のようにマッチしなければ*を含んだ文字列をそのままコマンドに渡しますが、shoptnullglobfailglobが設定されている場合は、引数がなくなったりエラーを吐いたりします。
さらに、zshだとエラーになるのがデフォルトです。

このあたりの挙動は以下の記事に詳しく書かれています。

17
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?