Разорвать все жесткие ссылки в папке

Вопрос или проблема

У меня есть папка, которая содержит определенное количество файлов с жесткими ссылками (в той же папке или где-то еще), и я хочу разорвать эти жесткие ссылки, чтобы файлы стали независимыми, и изменения в их содержимом не затрагивали другие файлы (их счетчик ссылок станет равным 1).

Ниже я приведу решение, которое по сути копирует каждую жесткую ссылку в другое место, а затем перемещает ее обратно на место.

Однако этот метод кажется довольно грубым и подверженным ошибкам, поэтому я хотел бы знать, есть ли команда, которая разорвет жесткую ссылку для меня.

Грубый ответ:

Найдите файлы, которые имеют жесткие ссылки (Правка: чтобы также найти сокеты и т.д., которые имеют жесткие ссылки, используйте find -not -type d -links +1):

find      -type f -links +1 # только файлы
find -not -type d -links +1 # файлы, сокеты и т.д.

Грубый метод разрыва жесткой ссылки (скопируйте ее в другое место и переместите обратно): Правка: Как сказал Celada, лучше выполнить cp -p ниже, чтобы избежать потери временных меток и прав доступа. Правка: Создайте временную директорию и копируйте файл в нее, вместо того чтобы перезаписывать временный файл, это минимизирует риск повреждения данных, хотя команда mv все еще рискованна (спасибо @Tobu). Правка: Старайтесь создавать временную директорию в одной файловой системе (@MikkoRantalainen).

# Это 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

Итак, чтобы разорвать все жесткие ссылки (Правка: изменено -type f на -not -type d, см. выше):

find -not -type d -links +1 -print0 | xargs -0 unhardlink.sh

В вашем скрипте есть возможность улучшения, например, добавление параметра -p к команде cp, чтобы сохранить права доступа и временные метки во время операции разрыва жесткой ссылки, и вы могли бы добавить обработку ошибок, чтобы временный файл удалялся в случае ошибки, но основная идея вашего решения является единственно возможной. Чтобы разорвать жесткую ссылку на файл, нужно скопировать его, а затем вернуть копию на оригинальное имя. Нет “менее грубого” решения, и это решение имеет состояние гонки в случае, если другой процесс одновременно обращается к файлу.

Если вы хотите занять место на диске, и у вас есть относительно современная версия tar (например, та, что есть на Ubuntu 10.04 и CentOS 6), вы можете поэкспериментировать с опцией --hard-dereference.

Что-то вроде:

$ cd /path/to/directory
$ ls -l *
bar:
total 12
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 1
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 3

foo:
total 12
-rw-rw-r-- 2 cjc cjc 3 May  6 19:07 1
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 4

(где я выполнил ln foo/[12] bar)

$ tar cvf /tmp/dereferencing.tar --hard-dereference .
$ tar xvf /tmp/dereferencing.tar
$ ls -l *
bar:
total 12
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 1
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 3

foo:
total 12
-rw-rw-r-- 1 cjc cjc 3 May  6 19:07 1
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 4

Из документации:

--hard-dereference

Разорвать жесткие ссылки и сохранить файлы, на которые они ссылаются.

Ответ или решение

Для задачи разбивки жестких ссылок (hard links) на файлы в папке и превращения их в независимые файлы существует несколько методов. Ниже приведены подробные инструкции, как это сделать с помощью простого скрипта и команды tar.

Метод 1: Скрипт для разбивки жестких ссылок

Создадим скрипт unhardlink.sh, который будет копировать файлы, чтобы удалить жесткие ссылки и сохранить исходные файлы. Вот пример скрипта:

#!/bin/bash
set -e

for file in "$@"; do
  temp_dir=$(mktemp -d -- "${file%/*}/hardlink-XXXXXXXX")
  cp -ip "$file" "$temp_dir/tempcopy"
  mv "$temp_dir/tempcopy" "$file"
  rmdir "$temp_dir"
done

Пояснения по скрипту:

  • set -e делает так, что скрипт завершит работу при возникновении любой ошибки.
  • mktemp создаёт временную директорию в том же каталоге, что и файл.
  • cp -ip копирует файл, сохраняя права доступа и временные метки; -i спрашивает перед перезаписью.
  • mv заменяет оригинальный файл новым, и временная директория удаляется через rmdir.

Запуск скрипта

Чтобы разбить все жесткие ссылки в папке, выполните следующую команду:

find -not -type d -links +1 -print0 | xargs -0 ./unhardlink.sh

Здесь find ищет файлы с более чем одной жесткой ссылкой и передает их в xargs, который запускает unhardlink.sh для каждого найденного файла.

Метод 2: Использование команды tar

Если у вас есть актуальная версия tar, вы можете использовать опцию --hard-dereference, которая разворачивает жесткие ссылки при создании архива.

Вот как это сделать:

  1. Перейдите в папку, содержащую файлы:
cd /путь/к/папке
  1. Запустите команду tar:
tar cvf /tmp/dereferencing.tar --hard-dereference .
  1. Извлеките содержимое архива:
tar xvf /tmp/dereferencing.tar

Этот метод создает копии всех файлов без жестких ссылок, таким образом разбивая их и делая независимыми.

Заключение

Оба метода эффективны, но выбор зависит от ваших требований. Скрипт может быть более гибким для управления отдельными файлами, тогда как tar может быть проще для работы с большими группами файлов. Рассмотрите использование первого метода для точечного контроля или второго для более быстрой работы с многочисленными файлами.

Оцените материал
Добавить комментарий

Капча загружается...