「cp -ra/. b」はなぜそのように動作するのでしょうか?

「cp -ra/. b」はなぜそのように動作するのでしょうか?

私はそう思っていましたaが、a/.同じ道です。しかし、私はcpそしてrsync/.ソース パスに が追加されると、ディレクトリ自体ではなくディレクトリの内容をコピーします。 も試しましたa/inner/..が、これもうまくいきました。

$ cp -r a b  # Copies dir a into dir b.
$ cp -r a/. b  # Copies files from dir a into dir b.
$ cp -r a/inner/.. b  # Also copies files from dir a into dir b.
$ cd a && cp -r . ../b  # One more way to copy inner files.

これは便利なのは理解しています。しかし、この機能は標準に違反しているようなので、少し混乱しています。

これはどのように機能するのでしょうか?この機能はどこかに文書化されていますか?これはOSの機能ですか?cpそれともbash?

答え1

これは便利なのは理解しています。しかし、この機能は標準に違反しているようなので、少し混乱しています。

cpa/.からに再帰的にコピーするときの動作は、bその「通常の」動作と完全に一致しています。

デフォルトでは、cpは親ディレクトリを作成しません。これは、両親スイッチ:

   --parents
          use full source file name under DIRECTORY

しかし、それはどういう意味でしょうか?

つまり、コマンド

cp --parents -r some/path/to/source dest

はソースディレクトリの内容をにコピーしますdest/some/path/to/source。コマンド

cp -r some/path/to/source dest

ソースディレクトリの内容を にコピーしますdest/source

同様に、コマンド

cp -r some/path/to/source/. dest

はソースディレクトリの内容を にコピーしますdest/.。これは のみですdest

aと思ったらa/.同じ道でした。

aそしてa/. 同じ道。しかし、cp、それは単なる文字列です。

コマンド

cp --parents -r some/path/to/source dest

そして

cd some/path/to && cp --parents -r source dest

動作も異なります。


はどうですかcp -r a/inner/.. b? あなたの説明を考慮すると、ファイルをb/..(つまり、現在のディレクトリに) コピーするべきではないでしょうか?

ええ、そうです。これは例外です。

少なくともGNU版ではcp、ベース名には特別なケースがあります..

からcoreutils-8.22/src/cp.c:

          if (parents_option)
            {
              [removed]
            }
          else
            {
              char *arg_base;
              /* Append the last component of 'arg' to 'target_directory'.  */

              ASSIGN_BASENAME_STRDUPA (arg_base, arg);
              /* For 'cp -R source/.. dest', don't copy into 'dest/..'. */
              dst_name = (STREQ (arg_base, "..")
                          ? xstrdup (target_directory)
                          : file_name_concat (target_directory, arg_base,
                                              NULL));
            }

目的は、宛先フォルダ外へのコピーを避けるためであると思われるが、これはcpの他のすべての場合の行動は、少し直感に反しており、不快な結果をもたらす可能性があります。

結局のところ、誰もその命令を期待していないと思う

cp -r .. ~

ホームディレクトリ外のファイルに影響を与える...

答え2

$ mkdir a b a/inner
$ touch a/a{1..3} b/b{1..3}
$ ls -R
.:
a  b

./a:
a1  a2  a3  inner

./a/inner:

./b:
b1  b2  b3
$ cp a b
cp: omitting directory ‘a’
$ cp a/. b
cp: omitting directory ‘a/.’
$ cp a/inner/.. b
cp: omitting directory ‘a/inner/..’
$ cd a && cp . ../b
cp: omitting directory ‘.’
$ cd ..
$ ls -R
.:
a  b

./a:
a1  a2  a3  inner

./a/inner:

./b:
b1  b2  b3

あなたが言うことはどれも実際には起こりません。4 つのcpコマンドは何も行いません。おそらく loaded のエイリアスがあるのでしょうcp。これを確認するには を使用しますalias cp

答え3

ところでrsync(1)、マニュアルを読んでください気をつけて. ここでは、「ディレクトリの内容」と「ディレクトリとその内容」を意味するために、いくつかの珍しい規則が使用されています。

cp(1)その他のLinuxコマンドについては、カーネルレベルaと、a/.まったくa/inner/..同じディレクトリを参照することさえあります。これは、アプリケーションがそれらを独自に解析して、奇妙な異なる意味を与えることができないという意味ではありませんが、文字列をカーネルに送信して、カーネルが適切な処理を実行する方が簡単です。

答え4

私の記憶が正しければ、この場合の . は * と同様に機能します。本質的には、ワイルドカード文字です。

関連情報