La página cp
del comando info
ofrece como opción --preserve=
lo siguiente:
links
Conserve en los archivos de destino cualquier vínculo entre los archivos de origen correspondientes. Tenga en cuenta quecon-L' or
-H', esta opciónpoderconvertir enlaces simbólicos en enlaces duros.
seguido de un ejemplo que no entiendo [ahora]; de todos modos:
Pregunta: ¿Cómo convertir enlaces suaves en enlaces duros cp
? ¿Y también hay un camino de regreso [convertir enlaces duros en enlaces suaves]?
Problema secundario: Donde hacepoderen la cita anterior entran en juego? Entiendo el propósito de -L
y -H
, puedo copiar enlaces suaves completamente funcionales, etc., pero hasta ahora no logré convertir enlaces suaves en enlaces duros.
Respuesta1
El ejemplo en la página de información le muestra cómo, aunque el ejemplo es un poco difícil de seguir:
$ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c
74161745 a
74161745 b
Dividamos eso en los comandos que lo componen:
mkdir c;
: crea el directorioc/
: > a;
: sólo una forma rápida de crear un archivo vacío. Es equivalente aecho "" > a
.:
es un bash integrado que no hace nada, consultehelp :
.ln -s a b
: crea un enlace suave paraa
llamarb
. En este punto, estos son los contenidos del directorio actual:$ ls -l | cc2ter total 4 -rw-r--r-- 1 terdon terdon 0 Oct 9 02:50 a lrwxrwxrwx 1 terdon terdon 1 Oct 9 02:50 b -> a drwxr-xr-x 2 terdon terdon 4096 Oct 9 02:50 c
Tenga en cuenta que
b
es un enlace simbólico (enlace suave) y no apunta al mismo inodo quea
:$ ls -i1c a b 16647344 a 16647362 b
cp -aH a b c;
: copiar archivosa
yb
al directorioc
. Aquí es donde ocurre la conversión, las opciones pasadascp
son:-a, --archive same as -dR --preserve=all -d same as --no-dereference --preserve=links -H follow command-line symbolic links in SOURCE
El
-H
es necesario porque (deinfo cp
):Al copiar desde un enlace simbólico, `cp' normalmente sigue al enlace sólo cuando no se copia de forma recursiva.
Dado que
-a
activa la copia recursiva (-R
),-H
es necesario seguir enlaces simbólicos.-H
significa que los enlaces se siguen a pesar de la recursividad y dará como resultado que se establezcan enlaces físicos en el directorio de destino. Estos son los contenidosc/
después del último paso (la primera columna es el número de inodo):$ ls -li c total 0 17044704 -rw-r--r-- 2 terdon terdon 0 Oct 9 02:50 a 17044704 -rw-r--r-- 2 terdon terdon 0 Oct 9 02:50 b
Ahora, en cuanto a cómo funciona exactamente, hasta donde puedo descifrar jugando con él, cp --preserve=links
se combina con enlaces simbólicos -L
o -H
los convertirá en enlaces físicos siTanto el enlace como el destino se están copiando almismodirectorio.
De hecho, como dice el OPdescubrí, al menos en sistemas Debian, cp --preserve=links
es suficiente para convertir enlaces simbólicos en enlaces físicos si el directorio de destino es el mismo.
Respuesta2
Envié un informe sobre un posible error al equipo de coreutils @gnu.org en info cp
la documentación y recibí esta respuesta:
Los documentos son un poco concisos aquí. El problema principal es que -a implica -d y eso implica --no-dereference que se requiere para que sus comandos funcionen como se esperaba. Se requiere IE --no-dereference para detener a cp implícitamente siguiendo enlaces simbólicos en la fuente.
Para verificar y dividir los detalles que se muestran aquí:
$ mkdir links; : > a; ln -s a b;
Aquí vemos que -d anula -H cuando viene después. Por lo tanto, en primer lugar, no eliminaremos la referencia a los enlaces simbólicos.
$ rm links/*; cp -H -d a b links $ l links/ lrwxrwxrwx. 1 padraig 1 Oct 10 09:37 b ▪▶ a -rw-rw-r--. 1 padraig 0 Oct 10 09:37 a
Aquí vemos que -H ahora se respeta porque aparece en último lugar y, por lo tanto, se siguen los enlaces simbólicos en el origen, lo que da como resultado enlaces físicos en el destino.
$ rm links/* $ rm links/*; cp -d -H a b links $ l links -rw-rw-r--. 2 padraig 0 Oct 10 09:37 b -rw-rw-r--. 2 padraig 0 Oct 10 09:37 a
Haré los documentos un poco más explícitos con lo siguiente:
diff --git a/doc/coreutils.texi b/doc/coreutils.texi index b273627..aeed4ca 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -8257,9 +8257,11 @@ $ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c @noindent
Tenga en cuenta las entradas:
@file{b}
es un enlace simbólico a un archivo normal@file{a}
, pero los archivos en el directorio de destino@file{c/}
están vinculados.
- Dado que
@option{-a}
implica@option{--preserve=links}
y que@option{-H}
indica@command{cp}
que se elimine la referencia a los argumentos de la línea de comando, ve dos archivos con el mismo número de inodo y conserva el vínculo físico percibido.- Dado que
@option{-a}
implica@option{--no-dereference}
que copiaría el enlace simbólico, pero luego@option{-H}
le indica@command{cp}
que elimine la referencia a los argumentos de la línea de comando donde luego ve dos archivos con el mismo número de inodo. Entonces la@option{--preserve=links}
opción también implicada por@option{-a}
preservará el vínculo duro percibido.
Respuesta3
Sería difícil convertir enlaces físicos en enlaces simbólicos. En el caso de un enlace físico, hay un bloque de datos en el sistema de archivos que tiene dos o más entradas de archivo apuntando hacia él. No hay "fuente" ni "destino"; es literalmente un archivo con múltiples nombres equivalentes. Puedes usar GNU find para identificarlos de esta manera:
sauer@zipper:~$ find . -type f -links +1 -printf "%i: %p (%n)\n"
609: ./link1 (2)
609: ./link2 (2)
Una vez que tenga todos los archivos con el mismo inodo, deberá elegir uno para que sea el archivo "real" y luego simplemente reemplazar todos los demás con enlaces simbólicos al archivo maestro. Probablemente la forma de hacerlo sería usar esto:
sauer@zipper:~$ find . -type f -links +1 -printf "%i %p\n" | sort -nk1
609 ./link1
609 ./link2
Y luego haga que un script descubra cómo elegir uno de los valores con el mismo número para que todos los demás se vinculen a él. Tal vez el primero se convierta en el objetivo, y todos los demás con el mismo inodo estén vinculados simbólicamente a él. Aquí hay un ejemplo de script de shell realmente simple y no probado
#!/bin/sh
prev=""
target=""
find /tmp -type f -links +1 -printf "%i %p\n" | sort -nk1 \
| while read inode file
do
if [[ $inode != $prev ]]
then
target="$file"
prev=$inode
else
ln -sf "$target" "$file"
fi
done
Existen problemas potenciales, ya que se pueden crear vínculos desde diferentes directorios con un destino no válido si la ruta en buscar (/tmp en este ejemplo) no es absoluta. Pero la idea general debería estar bien.