なぜ 'cp -r ../* .'は機能しますが、「cp -r ...」は機能しません。

なぜ 'cp -r ../* .'は機能しますが、「cp -r ...」は機能しません。

木がある場合:

.
├── child
├── dir1
├── dir2
├── dir3
├── file1
├── file2
└── file3

以下は、これらのコマンドを実行した結果ですchild。このコマンドは、すべてのファイルとディレクトリを操作してコピーします。

cp -r ../* .
----
cp: cannot copy a directory, '../child', into itself, './child'

これはchildファイルだけをコピーし、ディレクトリはコピーしません。

cp -r .. .
----
cp: cannot copy a directory, '..', into itself, '.'

答え1

実際に実行されたコマンドを表示します。

$ set -x; cp -r ../* .
+ cp -r ../child ../dir1 ../dir2 ../dir3 ../file1 ../file2 ../file3 .
cp: cannot copy a directory, '../child', into itself, './child'
$ set -x; cp -r .. .
+ cp -r .. .
cp: cannot copy a directory, '..', into itself, '.'

どちらのコマンドも、ディレクトリを独自にコピーしようとするとループが発生します。実装はcpこれを検出し、ある時点で停止または無期限のコピーを続行できます(たとえば、GNUやBusyBoxの停止cp、FreeBSDはcpファイル名の長さ制限に達するまでコピーを続けます。同様に、cpMacOSでもコピーは次のように続きます。U&Lについての他の質問提案されているようです)。
それにもかかわらず、ディレクトリを自分に再帰的にコピーすると、最終的にエラーが発生したときに停止します。

質問がGNU cp(GNU / Linuxシステム上のもの)に関するものであると仮定すると、通常2番目のコマンド(cp -r .. .)がコピーされます。(予測できない?)部分ツリーのルートで..ループを検出し、ツリー内のどのアイテムもさらに処理せずにエラーで停止します。

一方、最初のコマンド(cp -r ../* .)にはcp8つの個別の引数があります。childの内容のコピーに失敗すると、child他のディレクトリやファイルにはchild自分自身が含まれていないため、問題なくコピーされます。しかし、これは
ループを検出せず、継続的に再帰コピーを作成するシステムでは期待どおりに「動作」しません。cp


より安全な方法で親ディレクトリのすべての内容を現在のディレクトリ(child)にコピーするには(現在のディレクトリ自体を除く)、次のようにします。

$ shopt -s nullglob dotglob extglob
$ cp -r ../!(child) .

関連情報