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


10

У меня есть папка, которая содержит определенное количество файлов с жесткими ссылками (в той же папке или где-то еще), и я хочу де-хардлинкнуть эти файлы, чтобы они стали независимыми, и изменения в их содержимом не повлияют на другой файл (их количество ссылок становится равным 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

Таким образом, чтобы ООН-HardLink все жесткие ссылки ( Edit : изменен -type fна -not -type d, смотри выше):

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

Я не считаю это «сырым». Единственный способ сделать это быстрее - это, вероятно, сделать какой-то трюк с системным вызовом sendfile (), отсоединить файл с открытым исходным кодом и переписать целевой объект на месте. Честно говоря, это не стоит усилий, хотя.
Мэтью Ифе

Под «сырым» я подразумеваю, что, например, когда я запускал эту команду с помощью cp -iпереключателя, он высыпал на меня несколько сообщений, спрашивающих, должен ли он переопределить ./fileXXXXXX( $tempфайл), даже если tmpfile должен давать уникальные имена файлов, поэтому необходимо быть какое-то состояние гонки или что-то еще, и с этим риск потерять некоторые данные.
Сюзанна Дюперон,

1
Это нормально, что файл существует, вы просто создали его с помощью временного файла (nb: устарел в пользу mktemp, но это не является причиной вашей проблемы).
Тобу

1
Вам unhardlink.shследует создать временный каталог внутри того же каталога, в котором содержится файл, который необходимо удалить из ссылки. В противном случае ваш рекурсивный вызов может произойти в другой файловой системе, и вы в конечном итоге переместите материал за границы файловой системы, потому что ваш временный каталог находится в текущем рабочем каталоге. Я думаю, вы могли бы передать "$(dirname "$i")/hardlink-XXXXXX"в качестве аргумента mktemp вместо этого.
Микко Ранталайнен

1
@MikkoRantalainen Большое спасибо, обновлено! Обратите внимание, что если файловая система - это своего рода unionfs или fuseфайловая система, она может на самом деле отправлять данные path/to/hardlink-XXXна другой физический носитель информации path/to/original-file, но с этим ничего не поделаешь.
Сюзанна Дюперон

Ответы:


9

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


На самом деле, я всегда использую cp -a при копировании чего-либо, чтобы сохранить все, переписать и скопировать символические ссылки как символические ссылки. Не знаю, почему я забыл об этом в этот раз, но, увидев ваш ответ, я понял, что испортил все свои метки времени, и мне пришлось (довольно болезненно) восстановить их из резервной копии.
Сюзанна Дюперон

5

Если вы хотите сжечь дисковое пространство, и у вас есть относительно современная версия 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

Я подозреваю, что немного смолы не может сделать. Хорошее исправление.
Джозеф Керн

Я забыл упомянуть, что у меня не было достаточно места на диске, чтобы скопировать все. По сути, ваш метод такой же, как cp -a --no-preserve=links /path/to/folder /path/to/copy && rm -rf /path/to/folder && mv /path/to/copy /path/to/folder, если я не ошибаюсь. Я предполагаю, что ваш метод будет более эффективным, потому что tar будет задействовать меньше операций поиска на диске, а значит - меньше. Можно добиться того же с rsync, с еще более низкой производительностью, чем метод cp :).
Сюзанна Дюперон

1
Чтобы избежать использования большого количества дополнительного диска, можно запустить что-то подобное, tar cvf - --hard-dereference . | tar xf -но может быть состояние гонки, которое может привести к взрыву. Я не пробовал это, и я вроде не склонен делать это в данный момент.
CJC
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.