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

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

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

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

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

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

find      -type f -links +1 # files only
find -not -type d -links +1 # files, sockets etc.

Необработанный способ де-хардлинкнуть файл (скопировать его в другое место и переместить обратно): Редактировать: Как сказал Селада, лучше всего сделать cp -p ниже, чтобы избежать потери временных меток и разрешений. Редактировать: создать временный каталог и скопировать в файл под ним, вместо перезаписи временного файла, это минимизирует риск перезаписи некоторых данных, хотя mv Команда по-прежнему рискованно (спасибо @Tobu). Изменить: попробуйте создать временный каталог в той же файловой системе (@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

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

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

2 ответа

Решение

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

Если вы хотите сжечь дисковое пространство, и у вас есть относительно современная версия 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
          follow hard links; archive and dump the files they refer to
Другие вопросы по тегам