cp se comporta estranhamente quando. (ponto) ou .. (ponto ponto) são o diretório de origem

10

Esta resposta revela que é possível copiar todos os arquivos - incluindo os ocultos - do diretório src para o diretório dest como assim:

mkdir dest
cp -r src/. dest

Não há explicação na resposta ou nos seus comentários sobre o motivo pelo qual isso realmente funciona, e ninguém parece encontrar documentação sobre isso também.

Eu tentei algumas coisas. Primeiro, o caso normal:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src dest
$ ls -A dest
dest_file  src

Então, com /. no final:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/. dest
$ ls -A dest
dest_file  .dotfile  src_dir  src_file

Portanto, isso se comporta de maneira semelhante a * , mas também copia arquivos ocultos.

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/* dest
$ ls -A dest
dest_file  src_dir  src_file

. e .. são hard-links adequados como explicados aqui , assim como a entrada de diretório em si.

De onde vem esse comportamento e onde está documentado?

    
por iFreilicht 06.12.2017 / 15:40

1 resposta

20

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.

    
por 06.12.2017 / 15:49