Tengo una carpeta que contiene una cierta cantidad de archivos que tienen enlaces duros (en la misma carpeta o en otro lugar), y quiero des-enlazar estos archivos, para que se vuelvan independientes, y los cambios en su contenido no afectarán otro archivo (su recuento de enlaces se convierte en 1).
A continuación, doy una solución que básicamente copia cada enlace duro a otra ubicación, luego lo vuelvo a colocar en su lugar.
Sin embargo, este método parece bastante tosco y propenso a errores, por lo que me gustaría saber si hay algún comando que desvincule un archivo para mí.
Respuesta cruda:
Busque archivos que tengan enlaces duros ( Editar : para buscar también sockets, etc. que tengan enlaces duros , use find -not -type d -links +1
):
find -type f -links +1 # files only
find -not -type d -links +1 # files, sockets etc.
Un método burdo para desenlazar un archivo (copiarlo a otra ubicación y moverlo hacia atrás):
Editar: Como dijo Celada, es mejor hacer un cp -p a continuación, para evitar perder marcas de tiempo y permisos. Editar: cree un directorio temporal y cópielo en un archivo debajo de él, en lugar de sobrescribir un archivo temporal, minimiza el riesgo de sobrescribir algunos datos, aunque el mv
comando sigue siendo riesgoso (gracias @Tobu). Editar: intente crear el directorio temporal en el mismo sistema de archivos (@MikkoRantalainen).
# This is unhardlink.sh
set -e
for i in "$@"; do
temp="$(mktemp -d -- "${i%/*}/hardlnk-XXXXXXXX")"
[ -e "$temp" ] && cp -ip "$i" "$temp/tempcopy" && mv "$temp/tempcopy" "$i" && rmdir "$temp"
done
Entonces, para desvincular todos los enlaces duros ( Editar : cambiado -type f
a -not -type d
, ver arriba):
find -not -type d -links +1 -print0 | xargs -0 unhardlink.sh
cp -i
interruptor, me escupió algunos mensajes preguntándome si debería anular./fileXXXXXX
(el$temp
archivo), aunque tmpfile debería dar nombres de archivo únicos, por lo que debe ser algún tipo de condición de carrera o lo que sea, y con el riesgo de perder algunos datos.unhardlink.sh
debe crear el directorio temporal en el mismo directorio que contiene el archivo que necesita ser unhardlinked. De lo contrario, su llamada recursiva puede repetirse dentro de otro sistema de archivos y terminará moviendo cosas sobre los límites del sistema de archivos porque su directorio temporal está en el directorio de trabajo actual. Supongo que podrías pasar"$(dirname "$i")/hardlink-XXXXXX"
como argumento a mktemp en su lugar.fuse
sistema de archivos, en realidad podría enviarsepath/to/hardlink-XXX
a un medio de almacenamiento físico diferentepath/to/original-file
, pero no hay mucho que se pueda hacer al respecto.Respuestas:
Hay margen de mejora en su secuencia de comandos, por ejemplo, agregando una
-p
opción alcp
comando para que los permisos y las marcas de tiempo se conserven en toda la operación de desvinculación, y podría agregar algo de manejo de errores para que el archivo temporal se elimine en caso de error, pero la idea básica de su solución es la única que funcionará. Para desvincular un archivo, debe copiarlo y luego mover la copia nuevamente sobre el nombre original. No existe una solución "menos cruda", y esta solución tiene condiciones de carrera en caso de que otro proceso acceda al archivo al mismo tiempo.fuente
Si desea quemar espacio en el disco y tiene una versión relativamente moderna de
tar
(por ejemplo, qué hay en Ubuntu 10.04 y CentOS 6), puede jugar con la--hard-dereference
opción.Algo como:
(donde había corrido
ln foo/[12] bar
)Desde la página del manual:
fuente
cp -a --no-preserve=links /path/to/folder /path/to/copy && rm -rf /path/to/folder && mv /path/to/copy /path/to/folder
, si no me equivoco. Sin embargo, supongo que su método sería más eficiente, porque el alquitrán implicaría menos búsquedas de disco, por lo que menos agitación. Se podría lograr lo mismo con rsync, con un rendimiento aún menor que el método cp :).tar cvf - --hard-dereference . | tar xf -
pero puede haber una condición de carrera que hará que las cosas exploten. No lo he intentado, y no estoy dispuesto a hacerlo en este momento.