まずは、ちょっと揚げ足取りになりますが、質問にあるコマンドだとエラーになりますね。
「-r」オプションをつけている、と解釈します。
質問を見て、私も「アレ、そうなの?」と思いました。実際試してみると、確かにそのとおりですね。
「old
」と「old/.
」は同じファイルですので、
cp -r old/. new/
cp -r old new/
は同じ動きをするもの、と考えました。
というわけで、cpのソースコード
を追っかけてみました。
(見たソースはGNUのソースっぽいので、macとは違うかもしれませんが)
気になったのは、以下の点です。
c
1 char *arg_base;
2 /* Append the last component of 'arg' to 'target_directory'. */
3 ASSIGN_STRDUPA (arg_base, last_component (arg));
4 strip_trailing_slashes (arg_base);
5 /* For 'cp -R source/.. dest', don't copy into 'dest/..'. */
6 dst_name = (STREQ (arg_base, "..")
7 ? xstrdup (target_directory)
8 : file_name_concat (target_directory, arg_base,
9 NULL));
コメントで「Append the last component of 'arg' to 'target_directory'.」と書かれています。
日本語に訳すと「『arg』(これは、ソースファイルパスです)の『last component』を『target_directory』(コピー先パス)に追加する」ですね。
この「last component」とは何か、ちょっとそこまでソースを追いきれなかったのですが、想像すると「パスのスラッシュを区切りにして分割した物の最後の部分」(例えば、「aaa/bbb/ccc」というパスであれば「ccc」)と解釈します。
すると、どうでしょう。「old/.
」であれば、コピー先のパスは「new/.
」になり、「old
」であれば、コピー先のパスは「new/old
」になります。
つまり、「cp
コマンドは、コピー先のパスはコピー元のbasenameを追加したパスになるから」というのが答えのようです。