Вопрос или проблема
У меня есть папка, которая содержит определенное количество файлов с жесткими ссылками (в той же папке или где-то еще), и я хочу разорвать эти жесткие ссылки, чтобы файлы стали независимыми, и изменения в их содержимом не затрагивали другие файлы (их счетчик ссылок станет равным 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
, которая разворачивает жесткие ссылки при создании архива.
Вот как это сделать:
- Перейдите в папку, содержащую файлы:
cd /путь/к/папке
- Запустите команду
tar
:
tar cvf /tmp/dereferencing.tar --hard-dereference .
- Извлеките содержимое архива:
tar xvf /tmp/dereferencing.tar
Этот метод создает копии всех файлов без жестких ссылок, таким образом разбивая их и делая независимыми.
Заключение
Оба метода эффективны, но выбор зависит от ваших требований. Скрипт может быть более гибким для управления отдельными файлами, тогда как tar
может быть проще для работы с большими группами файлов. Рассмотрите использование первого метода для точечного контроля или второго для более быстрой работы с многочисленными файлами.