Разорвать жесткую ссылку на месте?

13

Я держу свои точечные файлы под контролем версий, а сценарий их развертывания создает жесткие ссылки. Я также использую, etckeeperчтобы поставить /etcпод контроль версий. Недавно я получил такие предупреждения:

warning: hard-linked files could cause problems with bzr

Простое копирование ( cp filename.ext filename.ext) не будет работать:

cp: `filename.ext' and `filename.ext' are the same file

Переименование / перемещение файла - за исключением разных томов - также не нарушает жесткую ссылку.

Итак, мой вопрос: есть ли способ разорвать жесткую ссылку на файл, фактически не имея необходимости знать, где находятся другие жесткие ссылки на этот файл?

0xC0000022L
источник
2
Команда "rm" разрывает жесткие ссылки.
Йохан

Ответы:

14
cp -p filename filename.tmp
mv -f filename.tmp filename

Делаем это скриптовым:

dir=$(dirname -- "$filename")
tmp=$(TMPDIR=$dir mktemp)
cp -p -- "$filename" "$tmp"
mv -f -- "$tmp" "$filename"

Делая копию сначала, а затем перемещая ее на место, преимущество в том, что файл атомарно превращается из твердой ссылки в отдельную копию (нет момента времени, когда он filenameявляется частичным или отсутствующим).

Жиль "ТАК - прекрати быть злым"
источник
7

Вы, вероятно, имеете в виду, что хотите разделить жесткую ссылку на отдельный независимый файл.

mv hardlink tempname && cp tempname hardlink && rm tempname

Жесткая ссылка - это связь между записью в каталоге и блоком inode на диске.

В inodes хранятся метаданные файла, а для небольших файлов некоторые файловые системы хранят данные в inode, в противном случае указатели на блоки данных, а для очень больших файлов - косвенные и двойные косвенные списки указателей на единицы размещения на диске.

Независимо от этого, соединение между именем файла (которое создает команда ls) и блоком inode, в котором хранятся эти метаданные, называется жесткой ссылкой.

Наличие нескольких жестких ссылок на один файл означает один и тот же индекс, на который ссылается более одной записи каталога, возможно, в разных каталогах (в одной файловой системе)

rm удаляет запись имени файла из каталога. Когда на индекс больше не ссылаются никакие файлы, его пространство освобождается для использования другими файлами.

Johan
источник
Действительно. Это то, что cpи mvпримеры. Так что я не вижу возможности использовать временный файл.
0xC0000022L
@ 0xC0000022L, нет, иноды не содержат указателей на другие иноды. Просто к блокам данных (или они могут удваиваться как пространство данных, если объект маленький).
vonbrand
4
Убедитесь, что разрешения и другие данные сохраняются при копировании, т.е. использовать cp -a(по крайней мере, GNU coreutils).
vonbrand
@ 0xC0000022L, если вы внимательно посмотрите, для исходного файла есть только временное имя, новый файл создается только на последнем шаге.
vonbrand
@vonbrand Они действительно могут, в зависимости от того, какая файловая система используется.
Йохан
4

Поместите это в конец вашего файла ~ / .bashrc.

delink () { tmpfile="$1$(date)"; cp -a "$1" "$tmpfile"; mv "$tmpfile" "$1"; }

Запустите это так

delink filename
Rucent88
источник
3

Лучший способ сделать это с помощью bash-скрипта - это что-то вроде этого:

if [ -f "$1" ] ; then
dir="$(dirname -- "$1")"
tmpfile="$(mktemp --tmpdir="$dir")"
cp --preserve=all -f -- "$1" "$tmpfile"
mv -f -- "$tmpfile" "$1"
fi

указывает на примечание:

  • проверьте, является ли файл обычным файлом, прежде чем пытаться скопировать его
  • сохраните старый файл на месте, пока копия не будет готова
  • использовать mktempдля создания файла, который гарантированно не существует
  • использовать -fдля принудительной перезаписи и --preserve=allсохранения метаданных, максимально похожих на исходный файл
  • использовать --и "указывать пути, содержащие пробелы и / или начинающиеся с-

Выполнение замены без создания временного файла невозможно с текущими (3.16) системными вызовами linux: хотя можно перезаписать файл атомарно (т. Е. Удалить старый файл и заменить новым как одну операцию), он это невозможно сделать с файлом, который не имеет имени в файловой системе (т. е. временный файл, созданный с использованием O_TMPFILEфлага openфункции), поскольку для renameфункции требуется имя файла в качестве входных данных (нет версии, renameкоторая принимает в качестве входных данных дескриптор файла - подробности смотрите здесь )

pqnet
источник
1
Обратите внимание, что вы не указали имя в вашем dirnameи mktempзвонки. Исправлено это для вас ...
Дероберт
@ derobert о, спасибо, но это не сработает, поскольку есть вложенные двойные кавычки ... нужно другое исправление! Kinda Hate Bash
pqnet
3
Это будет работать из-за $( ... )подстановки команды -style. Одна из причин, это лучше, чем ` ... `стиль.
Дероберт
@ Дероберт хорошо, не знал этого. Кроме того, как вы можете использовать `внутри теги встроенного кода?
pqnet
Вы можете избежать их с помощью обратной косой черты. Итак, чтобы `вы вставили: `\``(конечно, я дважды избежал этого, чтобы показать вам, что вы печатаете).
Дероберт
-1

Команда, которую вы ищете unlink

Дженни Д
источник
Возможно, мой вопрос был неясным, но «на месте» и примерами, cpи mvя хотел прояснить, что я хочу, чтобы файл существовал позже.
0xC0000022L
Ах, я не нашел это ясно, нет. Тогда вы должны пойти с ответом Йохана.
Дженни Д
1
Команда "unlink" просто удаляет файл (что делает системный вызов unlink ()).
Рауль Салинас-Монтеагудо
-1

Если вы ищете все имена файлов, которые имеют жесткую ссылку на этот файл, то вы можете использовать:

find -samefile myknowhardlinkfile

также ls -il myknowhardlinkfileпокажет вам номер файла, жестко связанный с тем же индексом (третье поле).

101612442 -rw-rw-r--. 2 me me 0 Aug  5 07:07 myknowhardlinkfile
Жан-Пьер Лаурин
источник
Это на самом деле не отвечает на вопрос, хотя это может быть полезно.
Флим