Как вы можете увидеть фактическую жесткую ссылку по ls?

135479
Léo Léopold Hertz 준영

я бегу

ln /a/A /b/B 

Я хотел бы видеть в папке, aгде файл A указывает на ls.

82
Жесткие ссылки не являются указателями, символические ссылки. Это несколько имен для одного и того же файла (inode). После системного вызова `link (2)` не имеет смысла, какой из них является оригиналом, а другой - ссылкой. Вот почему, как указывают ответы, единственный способ найти все ссылки - это `find / -samefile / a / A`. Потому что одна запись каталога для inode не «знает» о других записях каталога для того же inode. Все, что они делают, это пересчитывают индекс, чтобы его можно было удалить, когда его последним именем является «unlink (2) ed». (Это «количество ссылок» в выходных данных `ls`). Peter Cordes 9 лет назад 0
@PeterCordes: На самом ли деле учетная запись хранится в записи жесткой ссылки? Это то, что подразумевает ваша формулировка («Все, что они делают, это пересчитывают инод ...») Но это не имело бы смысла, если бы ссылки ничего не знали друг о друге, так как, когда одна обновляется, все остальные так или иначе должны будут быть обновленным. Или рефконт хранится в самом иноде? (Простите, если это глупый вопрос, я считаю себя новичком, и я все еще учусь). loneboat 8 лет назад 0
Рефконт хранится в inode, как вы, в конце концов, поняли, должно быть, исходя из других фактов. :) Записи в каталоге называются указателями на иноды. Мы называем это «жесткой связью», когда у вас есть несколько имен, указывающих на один и тот же индекс. Peter Cordes 8 лет назад 0

10 ответов на вопрос

150
zzr

Вы можете найти номер инода для вашего файла с

ls -i 

а также

ls -l 

показывает количество ссылок (количество жестких ссылок на определенный индекс)

после того как вы нашли номер инода, вы можете искать все файлы с одинаковым инодом:

find . -inum NUM 

покажет имена файлов для inode NUM в текущем каталоге (.)

Вы могли бы просто найти найти. имя файла BeowulfNode42 10 лет назад 42
@ BeowulfNode42 Эта команда великолепна, но для нее нужна как минимум общая корневая папка с теми же файлами. Itachi 7 лет назад 1
этот ответ дает прагматическое «сделай это», но я твердо уверен, что [@LaurenceGonsalves отвечает] (http://superuser.com/a/12973/28756) вопросы «как» и / или «почему». Trevor Boyd Smith 7 лет назад 1
55
Laurence Gonsalves

На самом деле нет четко определенного ответа на ваш вопрос. В отличие от символических ссылок, жесткие ссылки неотличимы от «оригинального файла».

Записи каталога состоят из имени файла и указателя на индекс. Индод, в свою очередь, содержит метаданные файла и (указатели на) фактическое содержимое файла). Создание жесткой ссылки создает другое имя файла + ссылку на тот же индекс. Эти ссылки являются однонаправленными (по крайней мере, в типичных файловых системах) - индекс хранит только счетчик ссылок. Не существует внутреннего способа узнать, какое имя файла является «оригинальным».

Кстати, именно поэтому системный вызов «удалить» файл называется unlink. Это просто удаляет жесткую ссылку. Индод, к которому прикреплены данные, удаляется только в том случае, если счетчик ссылок инода падает до 0.

Единственный способ найти другие ссылки на данный индекс - это провести тщательный поиск в файловой системе, проверяя, какие файлы ссылаются на рассматриваемый индекс. Вы можете использовать 'test A -ef B' из оболочки для выполнения этой проверки.

Это означает, что * нет такой вещи, как жесткая ссылка на другой файл *, поскольку исходный файл также является жесткой ссылкой; жесткие ссылки указывают на * местоположение на диске *. jtbandes 14 лет назад 30
@jtbandes: жесткие ссылки указывают на индекс, который указывает на фактические данные. dash17291 10 лет назад 9
32

UNIX имеет жесткие ссылки и символические ссылки (сделаны с "ln"и "ln -s"соответственно). Символические ссылки - это просто файл, который содержит реальный путь к другому файлу и может пересекать файловые системы.

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

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

Вы можете использовать "ls -i"команду, чтобы получить индекс определенного файла. Затем вы можете использовать "find <filesystemroot> -inum <inode>"команду, чтобы найти все файлы в файловой системе с указанным индексом.

Вот скрипт, который делает именно это. Вы вызываете это с помощью:

findhardlinks ~/jquery.js 

и он найдет все файлы в этой файловой системе, которые являются жесткими ссылками для этого файла:

pax@daemonspawn:~# ./findhardlinks /home/pax/jquery.js Processing '/home/pax/jquery.js' '/home/pax/jquery.js' has inode 5211995 on mount point '/' /home/common/jquery-1.2.6.min.js /home/pax/jquery.js 

Вот сценарий.

#!/bin/bash if [[ $# -lt 1 ]] ; then echo "Usage: findhardlinks <fileOrDirToFindFor> ..." exit 1 fi  while [[ $# -ge 1 ]] ; do echo "Processing '$1'" if [[ ! -r "$1" ]] ; then echo " '$1' is not accessible" else numlinks=$(ls -ld "$1" | awk '') inode=$(ls -id "$1" | awk '' | head -1l) device=$(df "$1" | tail -1l | awk '') echo " '$1' has inode $ on mount point '$'" find $ -inum $ 2>/dev/null | sed 's/^/ /' fi shift done 
@pax: Кажется, в скрипте есть ошибка. Я начинаю это с `. . / findhardlinks.bash`, находясь в OS X's Zsh. Мое текущее окно на экране закрывается. 14 лет назад 0
@Masi Проблема в твоих словах. (так же, как исходная команда). Это заставляет команду exit 1 выходить из вашей оболочки. Используйте chmod a + x findhardlinks.bash, затем выполните его с помощью ./findhardlinks.bash или используйте bash findhardlinks.bash njsf 14 лет назад 3
Пожалуйста, смотрите мой ответ на ваш ответ на http://superuser.com/questions/12972/to-see-hardlinks-by-ls/13233#13233 Léo Léopold Hertz 준영 14 лет назад 0
Чтобы сделать это программно, вероятно, будет более устойчивым, если вы используете это вместо этого: `INUM = $ (stat -c% i $ 1)`. Также `NUM_LINKS = $ (stat -c% h $ 1)`. Смотрите "man stat" для большего количества переменных формата, которые вы можете использовать. Joe 12 лет назад 1
Лучший ответ, безусловно. Престижность. MariusMatutiae 8 лет назад 0
Да, отличное объяснение с правильным ответом :) sMyles 6 лет назад 0
24
eyelidlessness
ls -l 

Первый столбец будет представлять разрешения. Во втором столбце будет указано количество подпунктов (для каталогов) или количество путей к тем же данным (жесткие ссылки, включая исходный файл) к файлу. Например:

-rw-r--r--@ 2 [username] [group] [timestamp] HardLink -rw-r--r--@ 2 [username] [group] [timestamp] Original ^ Number of hard links to the data 
Полезно для определения, если данный файл имеет [другие] жесткие ссылки, но не ГДЕ они являются. mklement0 9 лет назад 2
9
Loves Probability

Как насчет следующего более простого? (Последние могут заменить длинные сценарии выше!)

Если у вас есть конкретный файл <THEFILENAME>и вы хотите знать все его жесткие ссылки, распределенные по каталогу <TARGETDIR>(который может быть даже обозначен всей файловой системой /)

find <TARGETDIR> -type f -samefile <THEFILENAME> 

Расширяя логику, если вы хотите знать все файлы в <SOURCEDIR>нескольких жестких ссылках <TARGETDIR>:

find <SOURCEDIR> -type f -links +1 \ -printf "\n\n %n HardLinks of file : %H/%f \n" \ -exec find <TARGETDIR> -type f -samefile {} \;  
Это для меня лучший ответ! но я бы не использовал `-type f`, потому что файл тоже может быть каталогом. silvio 10 лет назад 0
@silvio: Вы можете создавать жесткие ссылки только на _files_, а не на каталоги. mklement0 9 лет назад 2
@ mklement0: Вы правы! silvio 9 лет назад 0
Записи `.` и` ..` в каталогах являются жесткими ссылками. Вы можете определить количество подкаталогов в каталоге по количеству ссылок `.`. В любом случае это спорный вопрос, так как `find -samefile .` по-прежнему не будет выводить какой-либо вывод` subdir / .. `. `find` (по крайней мере, версия GNU) кажется жестко закодированным, чтобы игнорировать` ..`, даже с `-noleaf`. Peter Cordes 9 лет назад 0
кроме того, идея find-all-links - `O (n ^ 2)`, и она запускает `find` один раз для каждого члена набора жестко связанных файлов. `find ... -printf '% 16i% p \ n' | сортировать -n | uniq -w 16 --all-repeat = Отдельный` будет работать, (16 недостаточно широк для десятичного представления 2 ^ 63-1, поэтому, когда ваша файловая система XFS достаточно велика, чтобы иметь номера индексов, которые высоки, следите ) Peter Cordes 9 лет назад 0
превратил это в ответ Peter Cordes 9 лет назад 0
4
Peter Cordes

There are a lot of answers with scripts to find all hardlinks in a filesystem. Most of them do silly things like running find to scan the whole filesystem for -samefile for EACH multiply-linked file. This is crazy; all you need is to sort on inode number and print duplicates.

find directories.. -xdev ! -type d -links +1 -printf '%20D %20i %p\n' | sort -n | uniq -w 42 --all-repeated=separate (Thanks to @Tino for tweaking my original command to support a FS-id (%D), and to handle all non-directory file types, not just regular files. This will find your multiply-linked symlinks, pipes, etc.)

Using ! -type d -links +1 means that sort's input is only as big as the final output of uniq. Unless you run it on a subdirectory that only contains one of a set of hardlinks. Anyway, this will use a LOT less CPU time re-traversing the filesystem than any other posted solution.

sample output:

... 2429 76732484 /home/peter/weird-filenames/test/.hiddendir/foo bar 2429 76732484 /home/peter/weird-filenames/test.orig/.hiddendir/foo bar 2430 17961006 /usr/bin/pkg-config.real 2430 17961006 /usr/bin/x86_64-pc-linux-gnu-pkg-config 2430 36646920 /usr/lib/i386-linux-gnu/dri/i915_dri.so 2430 36646920 /usr/lib/i386-linux-gnu/dri/i965_dri.so 2430 36646920 /usr/lib/i386-linux-gnu/dri/nouveau_vieux_dri.so 2430 36646920 /usr/lib/i386-linux-gnu/dri/r200_dri.so 2430 36646920 /usr/lib/i386-linux-gnu/dri/radeon_dri.so ... 

TODO?: un-pad the output. uniq has very limited field-selection support, so I pad the find output and use fixed-width. 20chars is wide enough for the maximum possible inode or device number (2^64-1 = 18446744073709551615). XFS chooses inode numbers based on where on disk they're allocated, not contiguously from 0, so large XFS filesystems can have >32bit inode numbers even if they don't have billions of files. Other filesystems might have 20-digit inode numbers even if they aren't gigantic.

TODO: sort groups of duplicates by path. Having them sorted by mount point then inode number mixes things together, if you have a couple different subdirs that have lots of hardlinks. (i.e. groups of dup-groups go together, but the output mixes them up).

A final sort -k 3 would sort lines separately, not groups of lines as a single record. Preprocessing with something to transform a pair of newlines into a NUL byte, and using GNU sort --zero-terminated -k 3 might do the trick. tr only operates on single characters, not 2->1 or 1->2 patterns, though. perl would do it (or just parse and sort within perl or awk). sed might also work.

`% D` - это идентификатор файловой системы (он уникален для текущей загрузки, в то время как никакие файловые системы не` umount`), поэтому следующее является еще более общим: `find directoryies .. -xdev! -типы d -links +1 -printf '% 20i% 20D% p \ n' | сортировать -n | uniq -w 42 - все повторяется = отдельно`. Это работает до тех пор, пока ни один каталог не содержит другой каталог на уровне файловой системы, а также он смотрит на все, что может быть жестко связано (например, устройства или программные ссылки - да, программные ссылки могут иметь количество ссылок больше 1). Обратите внимание, что сегодня `dev_t` и` ino_t` имеют длину 64 бита. Это, вероятно, будет продолжаться до тех пор, пока у нас есть 64-битные системы. Tino 8 лет назад 1
@Tino: замечательная идея использования `! -тип d` вместо `-типа f`. У меня даже есть несколько жестких ссылок в моей файловой системе для организации некоторых коллекций файлов. Обновил мой ответ вашей улучшенной версией (но я сначала поставил fs-id, так что порядок сортировки по крайней мере группируется по файловой системе.) Peter Cordes 8 лет назад 0
3
Daniel Andersson

Это своего рода комментарий к собственному ответу и сценарию Торокоро-Мачо, но он явно не помещается в поле для комментариев.


Переписал ваш сценарий, добавив более простые способы поиска информации и, таким образом, значительно меньше вызовов процессов.

#!/bin/sh xPATH=$(readlink -f -- "$") for xFILE in "$"/*; do [ -d "$" ] && continue [ ! -r "$" ] && printf '"%s" is not readable.\n' "$" 1>&2 && continue nLINKS=$(stat -c%h "$") if [ $ -gt 1 ]; then iNODE=$(stat -c%i "$") xDEVICE=$(stat -c%m "$") printf '\nItem: %s[%d] = %s\n' "$" "$" "$"; find "$" -inum $ -not -path "$" -printf ' -> %p\n' 2>/dev/null fi done 

Я старался сделать его максимально похожим на ваш, чтобы его можно было легко сравнить.

Комментарии к этому и вашему сценарию

  • Следует всегда избегать $IFSмагии, если достаточно глобуса, поскольку он излишне запутан, а имена файлов на самом деле могут содержать символы новой строки (но на практике это в основном первая причина).

  • Вы должны избегать ручного анализа lsи такого вывода в максимально возможной степени, так как это рано или поздно укусит вас. Например: в первой awkстроке вы ошибаетесь во всех именах файлов, содержащих пробелы.

  • printfв конце концов, часто избавляет от неприятностей, так как он очень устойчив с %sсинтаксисом. Он также дает вам полный контроль над выходом и в отличие от всех систем echo.

  • stat может сэкономить вам много логики в этом случае.

  • GNU find это мощный

  • Ваши вызовы headи tailвызовы могли быть обработаны напрямую, awkнапример, с помощью exitкоманды и / или выбора NRпеременной. Это сохранит вызовы процессов, что почти всегда значительно повышает производительность в трудолюбивых сценариях.

  • Ваши egrepс тем же успехом могут быть просто grep.

xDEVICE = $ (stat -c% m "$ ") не работает на всех системах (например: stat (GNU coreutils) 6.12). Если скрипт выдает «Item:?» в начале каждой строки, затем замените эту оскорбительную строку строкой, более похожей на оригинальный скрипт, но с xITEM, переименованным в xFILE: xDEVICE = $ (df "$ " | tail -1l | awk ' «) kbulgrien 10 лет назад 0
Если вам просто нужны группы жестких ссылок, а не повторяющиеся с каждым участником в качестве «мастера», используйте `find ... -xdev -type f -links +1 -printf '% 16i% p \ n' | сортировать -n | uniq -w 16 - все повторяется = отдельно`. Это НАМНОГО быстрее, так как проходит только один раз. Для нескольких FS, вам нужно префикс номера Inode с идентификатором FS. Может быть с `find -exec stat ... -printf ...` Peter Cordes 9 лет назад 0
превратил эту идею в ответ Peter Cordes 9 лет назад 0
2
Torocoro-Macho

Основываясь на findhardlinksсценарии (переименовал его в hard-links), это то, что я реорганизовал и заставил его работать.

Выход:

# ./hard-links /root  Item: /[10145] = /root/.profile -> /proc/907/sched -> /<some-where>/.profile  Item: /[10144] = /root/.tested -> /proc/907/limits -> /<some-where else>/.bashrc -> /root/.testlnk  Item: /[10144] = /root/.testlnk -> /proc/907/limits -> /<another-place else>/.bashrc -> /root/.tested 

 

# cat ./hard-links #!/bin/bash oIFS="$"; IFS=$'\n'; xPATH="$"; xFILES="`ls -al $|egrep "^-"|awk ''`"; for xFILE in $; do xITEM="$/$"; if [[ ! -r "$" ]] ; then echo "Path: '$' is not accessible! "; else nLINKS=$(ls -ld "$" | awk '') if [ $ -gt 1 ]; then iNODE=$(ls -id "$" | awk '' | head -1l) xDEVICE=$(df "$" | tail -1l | awk '') echo -e "\nItem: $[$iNODE] = $"; find $ -inum $ 2>/dev/null|egrep -v "$"|sed 's/^/ -> /'; fi fi done IFS="$"; echo ""; 
Я разместил комментарии к этому сценарию в качестве отдельного ответа. Daniel Andersson 11 лет назад 0
1
Charles

Решение с графическим интерфейсом действительно близко к вашему вопросу:

Вы не можете перечислить фактические жестко связанные файлы из «ls», потому что, как указывали предыдущие комментаторы, «имена» файлов являются просто псевдонимами к тем же данным. Однако на самом деле есть инструмент с графическим интерфейсом, который очень близок к тому, что вы хотите, который отображает список путей имен файлов, которые указывают на те же данные (как жесткие ссылки) в Linux, он называется FSLint. Требуемая опция находится в разделе «Конфликты имен» -> снимите флажок «$ PATH» в разделе «Поиск (XX) ->» и выберите «Псевдонимы» в раскрывающемся списке после «для ...» по направлению к верхней середине.

FSLint очень плохо документирован, но я обнаружил, что удостоверился, что ограниченное дерево каталогов в разделе «Путь поиска» с установленным флажком «Recurse?» и вышеупомянутые опции, список жестко связанных данных с путями и именами, которые «указывают» на одни и те же данные, создаются после поиска программы.

FSlint можно найти по адресу http://www.pixelbeat.org/fslint/. mklement0 9 лет назад 0
1
Daniel Sokolowski

Вы можете настроить lsвыделение жестких ссылок с помощью «псевдонима», но, как было сказано ранее, нет способа показать «источник» жесткой ссылки, поэтому я добавляю, .hardlinkчтобы помочь с этим.

выделить жесткие ссылки

Добавьте следующее где-то в вашем .bashrc

alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first' 

Похожие вопросы