convertir enlaces blandos a duros con cp

convertir enlaces blandos a duros con cp

La página cpdel comando infoofrece 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 -Ly -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 a echo "" > a. :es un bash integrado que no hace nada, consulte help :.
  • ln -s a b: crea un enlace suave para allamar b. 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 bes un enlace simbólico (enlace suave) y no apunta al mismo inodo que a:

    $ ls -i1c a b
    16647344 a
    16647362 b
    
  • cp -aH a b c;: copiar archivos ay bal directorio c. Aquí es donde ocurre la conversión, las opciones pasadas cpson:

    -a, --archive
          same as -dR --preserve=all
    -d    same as --no-dereference --preserve=links
    -H    follow command-line symbolic links in SOURCE
    

    El -Hes necesario porque (de info cp):

    Al copiar desde un enlace simbólico, `cp' normalmente sigue al enlace sólo cuando no se copia de forma recursiva.

    Dado que -aactiva la copia recursiva ( -R), -Hes necesario seguir enlaces simbólicos. -Hsignifica 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 contenidos c/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=linksse combina con enlaces simbólicos -Lo -Hlos 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=linkses 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 cpla 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.

información relacionada