У меня есть папка, которая содержит определенное количество файлов с жесткими ссылками (в той же папке или где-то еще), и я хочу де-хардлинкнуть эти файлы, чтобы они стали независимыми, и изменения в их содержимом не повлияют на другой файл (их количество ссылок становится равным 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
cp -i
переключателя, он высыпал на меня несколько сообщений, спрашивающих, должен ли он переопределить./fileXXXXXX
($temp
файл), даже если tmpfile должен давать уникальные имена файлов, поэтому необходимо быть какое-то состояние гонки или что-то еще, и с этим риск потерять некоторые данные.unhardlink.sh
следует создать временный каталог внутри того же каталога, в котором содержится файл, который необходимо удалить из ссылки. В противном случае ваш рекурсивный вызов может произойти в другой файловой системе, и вы в конечном итоге переместите материал за границы файловой системы, потому что ваш временный каталог находится в текущем рабочем каталоге. Я думаю, вы могли бы передать"$(dirname "$i")/hardlink-XXXXXX"
в качестве аргумента mktemp вместо этого.fuse
файловая система, она может на самом деле отправлять данныеpath/to/hardlink-XXX
на другой физический носитель информацииpath/to/original-file
, но с этим ничего не поделаешь.Ответы:
В вашем сценарии есть место для улучшения, например, добавление
-p
опции вcp
команду, чтобы разрешения и временные метки были сохранены для операции unhardlink, и вы могли бы добавить некоторую обработку ошибок, чтобы временный файл был удален в случае ошибки, но основная идея вашего решения - единственная, которая будет работать. Чтобы отменить привязку файла, вы должны скопировать его, а затем переместить копию обратно на оригинальное имя. Не существует «менее грубого» решения, и у этого решения есть условия состязания в случае, если другой процесс одновременно обращается к файлу.источник
Если вы хотите сжечь дисковое пространство, и у вас есть относительно современная версия
tar
(например, что на Ubuntu 10.04 и CentOS 6), вы можете поиграть с этой--hard-dereference
опцией.Что-то типа:
(где я бегал
ln foo/[12] bar
)Со страницы руководства:
источник
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 :).tar cvf - --hard-dereference . | tar xf -
но может быть состояние гонки, которое может привести к взрыву. Я не пробовал это, и я вроде не склонен делать это в данный момент.