cp se comporta de manera extraña cuando. (punto) o .. (punto punto) son el directorio fuente


15

Esta respuesta revela que uno puede copiar todos los archivos, incluidos los ocultos, del directorio srcal directorio de la siguiente destmanera:

mkdir dest
cp -r src/. dest

No hay una explicación en la respuesta o en sus comentarios sobre por qué esto realmente funciona, y nadie parece encontrar documentación sobre esto tampoco.

Probé algunas cosas. Primero, el 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

Luego, con /.al 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

Entonces, esto se comporta de manera similar a *, pero también copia archivos 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

.y ..son enlaces duros adecuados como se explica aquí , al igual que la entrada del directorio en sí.

¿De dónde viene este comportamiento y dónde está documentado?


3
¿Qué quieres decir con que nadie puede encontrar documentación? La cpreferencia explica claramente cómo cp -Rfunciona. .y ..son directorios como cualquier otro directorio, no hay nada mágico o misterioso en ellos.
AlexP

2
@AlexP Edité la respuesta para aclararla. El punto es que ., y ..no se comportan como otros directorios.
iFreilicht

Respuestas:


27

El comportamiento es un resultado lógico del algoritmo documentado para cp -R. Ver POSIX , paso 2f:

Los archivos en el directorio source_file se copiarán en el directorio dest_file , siguiendo los cuatro pasos (1 a 4) enumerados aquí con los archivos como source_files .

.y ..son directorios, respectivamente, el directorio actual y el directorio padre. Ninguno de los dos es especial en lo que respecta al shell, por lo que ninguno se preocupa por la expansión, y el directorio se copiará, incluidos los archivos ocultos. *, por otro lado, se expandirá a una lista de archivos, y aquí es donde se filtran los archivos ocultos.

src/.es el directorio actual dentro src, que es en srcsí mismo; src/src_dir/..es src_direl directorio padre, que es nuevamente src. Entonces, desde afuera src, si srces un directorio, especificar src/.o src/src_dir/..como el archivo fuente cpes equivalente y copiar el contenido de src, incluidos los archivos ocultos.

El punto de especificar src/.es que fallará si srcno es un directorio (o enlace simbólico a un directorio), mientras srcque no lo haría. También copiará el contenido de srcsolo, sin copiarse a srcsí mismo; esto también coincide con la documentación:

Si el destino existe y nombra un directorio existente, el nombre de la ruta de destino correspondiente para cada archivo en la jerarquía de archivos será la concatenación de destino , un solo carácter de barra diagonal si el destino no terminó en una barra diagonal y el nombre de ruta del archivo relativo al directorio que contiene el archivo fuente .

Entonces cp -R src/. destcopia el contenido de srcto dest/.(el archivo fuente está .en src), mientras que cp -R src destcopia el contenido de srcto dest/src(el archivo fuente está src).

Otra forma de pensar en esto es comparar la copia src/src_diry src/., en lugar de comparar src/.y src. .se comporta como src_diren el primer caso.


Pero no se comporta de la misma manera. Especificar srccopiará el directorio dest, src/.copiará el contenido. Trataré de aclarar eso en la pregunta.
iFreilicht

Allí, creo que eso responde a su pregunta subyacente.
Stephen Kitt

1
@ Stéphane el OP compara la copia src/.y src/*(nota, no src/.* ); src/*no incluye archivos ocultos si globbing los ignora ...
Stephen Kitt

1
Hmm, "directorio que contiene el archivo fuente ". Bueno, obviamente srccontiene src/.pero significa que el directorio que contiene un directorio depende de cómo se nombre el directorio. Por supuesto, la existencia de los .enlaces de alguna manera significa que todos los directorios se contienen a sí mismos, pero eso podría no ser intuitivo para todos. En lugar de este comportamiento, uno también podría verse tentado a suponer que "el directorio que contiene el directorio foo" estaría determinado por foo/.., en cuyo caso no importaría si nos referimos a fooo foo/.: el directorio que contiene sería el mismo.
ilkkachu

1
Lo que quiere decir que la distinción entre fooy foo/.parece un poco delicada, pero no me importa, también me parece un poco divertido.
ilkkachu

1

Cuando corras cp -R src/foo dest, lo conseguirás dest/foo. Entonces, si el directorio dest/foono existe, cplo creará y luego copiará el contenido de src/fooa dest/foo.

Cuando ejecuta cp -R src/. dest, cpve que dest/.existe, y luego es solo cuestión de copiar el contenido de src/.a dest/..

Cuando se piensa en ello como copiar un directorio con el nombre .de srcy la fusión de su contenido con el directorio existente dest/., tendrá sentido.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.