Linux の cp コマンドでフォルダをコピーするときのスラッシュとワイルドカードの使い方まとめ

ようやく、cp でディレクトリをコピーするときのさまざまなケースをまとめた。ディレクトリも特殊なファイルの一種だが、コピー時にはやはり混同しやすい点がいくつかある。特に、コピー元パス末尾の /、ワイルドカード *、そしてコピー先ディレクトリがすでに存在するかどうかだ。

以下では [^] をスペースとして表す。/a ディレクトリの下に、ファイルまたはサブディレクトリ 123 があるものとする。

cp[^]-R[^]/a/*[^]/b

次と同じ意味になる。

cp -R /a/* /b/

これは /a ディレクトリ配下で * にマッチする内容を /b ディレクトリ配下へコピーする。つまり、コピーされるのは /a の中にある各ファイルやサブディレクトリであり、/a ディレクトリそのものではない。

注意点は 2 つある。

  1. * は shell によって展開され、デフォルトでは .gitignore.env.config などの隠しファイルにはマッチしない。
  2. /a の下にサブディレクトリがある場合、それらを再帰的にコピーするには -R または -r を付ける必要がある。現代の GNU coreutils では、-R-r は通常同等だが、移植性を重視するなら POSIX で規定されている -R を優先して使う。

隠しファイルもまとめてコピーしたい場合は、次のようにすることを検討できる。

cp -R /a/. /b/

ここでの /a/. は、通常ファイル、隠しファイル、サブディレクトリを含めて、/a の内容を /b へコピーすることを意味する。

cp[^]-R[^]/a[^]/b/c

この書き方は、コピー先パス /b/c がすでに存在するかどうかで 2 つの場合に分けて考える必要がある。

/b/c が存在しない場合

コマンドは /b/c を作成し、/a の中にあるすべてのファイルとサブディレクトリを /b/c の中へコピーする。効果としては、/a を新しいディレクトリ /b/c としてクローンするのに相当する。

cp -R /a /b/c

コピー後の構造は次のようになる。

/b/c/1
/b/c/2
/b/c/3

/b/c がすでに存在する場合

コマンドは /a ディレクトリそのものを /b/c の中へコピーする。コピーが成功すると、ディレクトリ構造は次のようになる。

/b/c/a/1
/b/c/a/2
/b/c/a/3

つまり、コピー先ディレクトリがすでに存在する場合、cp -R /a /b/c の結果は /a の内容を /b/c に平置きするのではなく、/b/c の下にさらに a ディレクトリを作成することになる。

cp[^]-R[^]/a/[^]/b

GNU/Linux で一般的な cp 実装では、コピー元パス末尾の / は、ディレクトリをコピーするときの主な挙動を通常は変えない。つまり、

cp -R /a/ /b

は、通常は次のコマンドとほぼ同じ結果になる。

cp -R /a /b

/b がすでに存在する場合、コピー後の結果は一般に次のようになる。

/b/a/1
/b/a/2
/b/a/3

-R または -r を付けていない場合に限り、次のようなエラーが出る。

cp: omitting directory '/a/'

cp[^]-R[^]/a/[^]/b/

コピー先パス末尾の / は、コピー先がディレクトリであるべきことを示す。そのため、

cp -R /a/ /b/

は、/b がすでに存在する場合、通常 /a ディレクトリを /b の下へコピーし、結果は次のようになる。

/b/a/1
/b/a/2
/b/a/3

/b が存在しない場合、システムやバージョンによってエラーメッセージは多少異なることがある。実際に使う前に、次のコマンドで手元の環境での挙動を確認できる。

mkdir -p /tmp/cp-test/a
printf 'onen' > /tmp/cp-test/a/1
printf 'twon' > /tmp/cp-test/a/2
printf 'threen' > /tmp/cp-test/a/3
mkdir -p /tmp/cp-test/b
cp -R /tmp/cp-test/a/ /tmp/cp-test/b/
find /tmp/cp-test -maxdepth 3 -type f | sort

まとめ

よく使う結論は次のとおり。

cp -R /a/* /b/

/a の中で * にマッチした内容を /b へコピーする。デフォルトでは隠しファイルは含まれない。

cp -R /a/. /b/

隠しファイルを含め、/a の中身をすべて /b へコピーする。

cp -R /a /b/c

/b/c が存在しなければ、/a/b/c としてクローンする。/b/c がすでに存在すれば、/a/b/c/a としてコピーする。

cp -R /a/ /b/

一般的な GNU/Linux 環境では、コピー元パス末尾の / によって cp がディレクトリの中身だけをコピーするようになるわけでは通常ない。ディレクトリそのものではなく中身をコピーしたい場合は、cp -R /a/. /b/ と書くほうが明確である。

Leave a Reply