Розбийте всі тверді посилання всередині папки


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

Отже, для від’єднання всіх жорстких посилань ( Правка : змінено -type fна -not -type d, див. Вище):

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

Я б не вважав це "сирим". Єдиний спосіб зробити це швидше - це, мабуть, зробити якийсь фокус із системним викликом sendfile () та від’єднати файл з відкритим кодом та переписати цільове місце. Відверто кажучи, це не варте зусиль, хоча.
Метью Іфе

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

1
Це нормально, що файл існує, ви просто створили його за допомогою tempfile (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команди, щоб дозволи та часові позначки зберігалися протягом операції відключення посилання, і ви можете додати деяку обробку помилок, щоб тимчасовий файл був видалений у разі помилки, але основна ідея вашого рішення є єдиною, яка буде працювати. Для від’єднання файлу потрібно скопіювати його, а потім перемістити копію назад над початковим іменем. Немає "менш грубого" рішення, і це рішення має змагальні умови, якщо інший процес одночасно отримує доступ до файлу.


Дійсно, я завжди використовую 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, якщо я не помиляюся. Я думаю, що ваш метод був би більш ефективним, оскільки смола залучає менше запитів дисків, тим менше обмолотів. Цього можна було б досягти і при rsync, з навіть меншою продуктивністю, ніж метод cp :).
Сюзанна Дюперон

1
Щоб уникнути використання багато зайвого диска, можливо, можна запустити щось на кшталт, tar cvf - --hard-dereference . | tar xf -але може бути стан гонки, який призведе до вибуху. Я ще не пробував цього, і на даний момент я не хочу це робити.
cjc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.