Cómo copiar un directorio de forma recursiva utilizando enlaces duros para cada archivo

52

Quiero crear una "copia" de un árbol de directorios donde cada archivo es un enlace al archivo original

Ejemplo: tengo una estructura de directorio:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

Aquí está el resultado esperado, una "copia" del árbol de directorios donde cada archivo es un enlace rígido al archivo original:

dirB/            #  normal directory
dirB/file1       #  hardlink to dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  hardlink to dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  hardlink to dirA/y/file3
Gudmundur Orn
fuente

Respuestas:

50

En Linux (más precisamente con el GNU y las busyboximplementaciones cpque normalmente se encuentran en sistemas que tienen Linux como núcleo) y FreeBSD reciente, así es como:

cp -al dirA dirB

Para una solución más portátil, vea la respuesta usando pax y cpio por Stéphane Chazelas

Gudmundur Orn
fuente
Tenga en cuenta que pax, como en FreeBSD, cp -ano enlaza los enlaces simbólicos.
Stéphane Chazelas
Tenga en cuenta que los enlaces duros no funcionan en montajes de sistema de archivos separados.
Dave
24

POSIXY, usaría paxen modo lectura + escritura con la -lopción:

pax -rwlpe -s /A/B/ dirA .

( -peConserva todos los atributos posibles de archivos (en este caso sólo directorios) que se copian, como GNU cp's -ahace).

Ahora, aunque estándar , ese comando no es necesariamente muy portátil .

Primero, muchos sistemas basados ​​en GNU / Linux no se incluyen paxpor defecto (a pesar de que es una utilidad POSIX no opcional).

Luego, varios errores y no conformidades con algunas implementaciones causan varios problemas con ese código.

  • debido a un error, Solaris 10 pax(al menos) no funciona cuando se usa -rwlen combinación con -s. Por alguna razón, parece que aplica la sustitución tanto a la ruta original como a la copiada. Así que arriba, intentaría hacer algo en link("dirB/file", "dirB/file")lugar de link("dirA/file", "dirB/file").
  • en FreeBSD, paxno crea enlaces duros para archivos de tipo enlace simbólico (un comportamiento permitido por POSIX). No solo eso, sino que también aplica la sustitución a los objetivos de los enlaces simbólicos (un comportamiento no permitido por POSIX). Entonces, por ejemplo, si hay un foo -> AAenlace simbólico dirA, se convertirá foo -> BAen dirB.

Además, si desea hacer lo mismo pero con rutas de archivos arbitrarias cuyo contenido está almacenado $srcy $dst, es importante darse cuenta de que pax -rwl -- "$src" "$dst"crea la estructura de directorio completa de $srcdentro $dst(que tiene que existir y ser un directorio). Por ejemplo, si $srces foo/bar, entonces, $dst/foo/barse crea.

Si, en cambio, desea $dstser una copia de $src, lo más fácil es probablemente hacerlo como:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && pax -rwlpe . "$absolute_dst")

(que también solucionaría la mayoría de los problemas mencionados anteriormente, pero fallaría si la ruta absoluta de $dsttermina en caracteres de nueva línea).

Ahora eso no ayudará en los sistemas GNU / Linux donde no hay pax.

Es interesante notar que paxfue creado por POSIX para fusionar las características de los comandos tary cpio.

cpioes un comando histórico de Unix (de 1977) en oposición a una invención POSIX, y también hay una implementación de GNU (no una pax). Entonces, aunque ya no es un comando estándar (aunque estaba en SUSv2), sigue siendo muy común y hay un conjunto básico de características en las que generalmente puede confiar.

El equivalente de pax -rwlsería cpio -pl. Sin embargo:

  1. cpio toma la lista de archivos de entrada en stdin en lugar de argumentos (nueva línea delimitada, lo que significa que los nombres de archivo con caracteres de nueva línea no son compatibles)
  2. Todos los archivos tienen que especificarse (por lo general, se alimenta con la salida de find( findy cpiofueron desarrollados conjuntamente por las mismas personas)).
  3. los metadatos no se conservan (algunas cpioimplementaciones tienen opciones para preservar algunas, pero nada portátil).

Entonces con cpio:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && find . | cpio -pl "$absolute_dst")
Stéphane Chazelas
fuente
Parece que -s / A / B / es específico de mi ejemplo. ¿Cómo haría esto si el nombre del directorio de origen y el nombre del directorio de destino fueran variables $ sourcedir y $ targetdir?
Gudmundur Orn
@GudmundurOrn, ver edición.
Stéphane Chazelas
Ejecuto este comando en OS X y recibo un mensaje de error "pax: No se puede vincular el archivo ./a.txt a sí mismo". Usé el comando your literalmente, simplemente reemplazando el directorio de origen con el nombre real, dejando / A / B y el punto final como está. ¿Estoy malinterpretando algo?
db
@db, -s /A/Breemplaza Acon Bpara que se dirAconvierta dirB. Si el nombre del directorio de origen no tiene A, entonces eso lo copiará (vinculará) sobre sí mismo. Vea también el resto de la respuesta para posibles enfoques mejores.
Stéphane Chazelas
6

Respuesta corta:

cd $source_folder
pax -rwlpe . $dest_folder
lkraider
fuente
2

En caso de que esté buscando esa función de copiar con enlaces duros para hacer instantáneas o copias de seguridad de (todos o parte de) sus archivos, eche un vistazo rsnapshot.

Janis
fuente
1
Eso es interesante. Pero supongo que los enlaces duros son solo un buen mecanismo de instantánea si los archivos no se modificarán. ¿Derecho?
Gudmundur Orn
@Gudmundur Orn; Esto es correcto. La herramienta mencionada en mi respuesta creará una nueva instantánea de manera que los archivos sean únicos; es decir, los archivos existentes (no modificados) se crearán como enlaces duros y los archivos nuevos (o versiones modificadas de archivos existentes) se crearán como archivos nuevos. En consecuencia, tendrá la menor redundancia.
Janis
0

La respuesta de @ gudmundur-orn es correcta, pero si estás en BtrFS en Linux cp a --reflink=auto dirA dirBdebería hacer el truco, con la diferencia de que los archivos son realmente diferentes y cambiar uno no cambia el otro. Puede lograr casi lo mismo con cp -cuna Mac con APFS ( autohará una copia completa si no es posible, -cfallará).

Cualquier sistema de archivos COW debería poder hacerlo, pero los proveedores no han acordado una opción de línea de comando estándar.

rbanffy
fuente