O comportamento é um resultado lógico do algoritmo documentado para cp -R . Veja POSIX , passo 2f:
The files in the directory source_file shall be copied to the directory dest_file, taking the four steps (1 to 4) listed here with the files as source_files.
. e .. são diretórios, respectivamente, o diretório atual e o diretório pai. Nenhum deles é especial no que diz respeito ao shell, portanto, nenhum deles está preocupado com a expansão (o que evita problemas com o shell que está expandindo arquivos ocultos ou não). src/. é o diretório atual dentro de src , que é src ; src/src_dir/.. é o diretório pai de src_dir , que é novamente src . Portanto, de fora de src , se src for um diretório, especificar src/. ou src/src_dir/.. como o arquivo de origem para cp será equivalente e copiar o conteúdo de src .
O ponto de especificar src/. é que ele falhará se src não for um diretório (ou link simbólico para um diretório), enquanto src não. Ele também copiará o conteúdo de src , sem copiar o próprio src ; isso corresponde à documentação também:
If target exists and names an existing directory, the name of the corresponding destination path for each file in the file hierarchy shall be the concatenation of target, a single slash character if target did not end in a slash, and the pathname of the file relative to the directory containing source_file.
Portanto, cp -R src/. dest copia o conteúdo de src para dest/. (o arquivo de origem é . em src ), enquanto cp -R src dest copia o conteúdo de src para dest/src (a origem o arquivo é src ).
Outra maneira de pensar nisso é comparar a cópia src/src_dir e src/. , em vez de comparar src/. e src . . se comporta como src_dir no primeiro caso.