Як ви можете бачити фактичне жорстке посилання за ls?


97

я біжу

ln /a/A /b/B

Я хотів би бачити в папці , aде знаходяться точки файла A до шляху ls.


1
Жорсткі посилання не є покажчиками, символьні посилання. Вони кілька імен для одного файлу (inode). Після link(2)системного дзвінка немає сенсу, у якому один є оригіналом, а хто - посиланням. Ось чому, як вказують відповіді, єдиний спосіб знайти всі посилання - це find / -samefile /a/A. Оскільки один запис каталогу для inode не "знає про" інші записи каталогів для того ж inode. Все, що вони роблять, - це перерахунок inode, щоб його можна було видалити, коли прізвище є unlink(2)ed. (Це "кількість посилань" у lsвиході).
Пітер Кордес

@PeterCordes: Чи фактично зберігається знижка в записі жорсткого посилання? Ось що означає ваше формулювання ("Все, що вони роблять, - це перерахунок inode ...") Але це не мало б сенсу, якщо посилання нічого не знають одне про одного, оскільки, коли один оновлений, всі інші якось повинні були бути оновленим. Або знижка зберігається в самій inode? (Пробачте, якщо це німе питання, я вважаю себе новачком і все ще вчуся).
самотній човен

1
Знижка зберігається в inode, як ви, зрештою, з'ясували, що це стосується інших фактів. :) Записи каталогів названі вказівниками на inode. Ми називаємо це "жорстким зв'язком", коли у вас є кілька імен, що вказують на один і той же індед.
Пітер Кордес

Відповіді:


171

Ви можете знайти номер inode для вашого файлу за допомогою

ls -i

і

ls -l

показує кількість посилань (кількість жорстких посилань на певний inode)

знайшовши номер inode, ви можете шукати всі файли з однаковим inode:

find . -inum NUM

покаже назви файлів для inode NUM у поточному режимі (.)


46
Ви можете просто запустити пошук. -samefile filename
BeowulfNode42

1
@ BeowulfNode42 Ця команда чудова, але їй потрібна спільна коренева папка тих самих файлів.
Ітачі

1
ця відповідь дає прагматичне "зроби це", але я сильно відчуваю, що @LaurenceGonsalves відповідає на питання "як" та / або "чому".
Тревор Бойд Сміт

65

Насправді немає чітко визначеної відповіді на ваше запитання. На відміну від символьних посилань, жорсткі посилання не відрізняються від "оригінального файлу".

Записи каталогів складаються з імені файлу та вказівника на індекс. Inode, в свою чергу, містить метадані файлу та (вказує на) фактичний вміст файлу). Створення жорсткого посилання створює інше ім'я файлу + посилання на той самий вхід. Ці посилання є односпрямованими (як мінімум у типових файлових системах) - inode зберігає лише кількість посилань. Немає внутрішнього способу дізнатися, яке саме "оригінальне" ім'я файлу.

До речі, саме тому викликається системний виклик для "видалення" файлу unlink. Це просто видаляє жорстке посилання. Вкладені дані inode видаляються лише в тому випадку, якщо посилальне число inode падає до 0.

Єдиний спосіб знайти інші посилання на даний інод - це вичерпний пошук файлової системи, перевіряючи, які файли відносяться до відповідної індеди. Ви можете використовувати 'test A -ef B' з оболонки для здійснення цієї перевірки.


35
Це означає, що немає такого твердого посилання на інший файл , оскільки вихідний файл також є жорстким посиланням; жорсткі посилання вказують на місце на диску .
jtbandes

12
@jtbandes: жорсткі посилання вказують на індекс, який вказує на фактичні дані.
dash17291

33

UNIX має жорсткі посилання та символічні посилання (зроблені відповідно "ln"і "ln -s"відповідно). Символічні посилання - це просто файл, який містить реальний шлях до іншого файлу і може перетинати файлові системи.

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

Оскільки вставки унікальні лише для даної файлової системи, існує обмеження, що жорсткі посилання повинні бути в одній файловій системі (на відміну від символічних посилань). Зауважте, що на відміну від символічних посилань, привілейований файл не існує - всі вони рівні. Область даних буде випущена лише тоді, коли всі файли, які використовують цей inode, будуть видалені (і всі процеси також закриваються, але це вже інше питання).

Ви можете скористатися "ls -i"командою для отримання inode певного файлу. Потім ви можете скористатися "find <filesystemroot> -inum <inode>"командою для пошуку всіх файлів у файловій системі із заданим 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 '{print $2}')
        inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
        device=$(df "$1" | tail -1l | awk '{print $6}')
        echo "   '$1' has inode ${inode} on mount point '${device}'"
        find ${device} -inum ${inode} 2>/dev/null | sed 's/^/        /'
    fi
    shift
done

@pax: Схоже, помилка в сценарії. Я запускаю це, . ./findhardlinks.bashперебуваючи в Zsh OS X. Моє поточне вікно в екрані закривається.

4
@Masi Проблема є вашою початковою. (те саме, що і вихідна команда). Це призводить до того, що команда exit 1 вийде з вашої оболонки. Використовуйте chmod a + x findhardlinks.bash, а потім виконайте його ./findhardlinks.bash або використовуйте bash findhardlinks.bash
njsf

Будь ласка, дивіться мою відповідь на вашу відповідь на superuser.com/questions/12972/to-see-hardlinks-by-ls/…
Léo Léopold Hertz '26

3
Щоб зробити це програмно, це, ймовірно , більш стійкими , якщо ви використовуєте замість цього: INUM=$(stat -c %i $1). Також NUM_LINKS=$(stat -c %h $1). Перегляньте man statдодаткові змінні формату, які ви можете використовувати.
Джо

Найкраща відповідь, на сьогоднішній день. Кудос.
MariusMatutiae

24
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

2
Корисний при визначенні ІФ у конкретному файлі є [інші] жорсткі посилання, але не те, де вони є.
mklement0

Крім того, між жорсткою посиланням та оригінальним файлом немає технічної різниці. Вони обидва однакові тим, що просто вказують на те, inodeщо в свою чергу вказує на вміст диска.
guyarad

13

Як щодо наступного простішого? (Пізніший варіант може замінити довгі сценарії вище!)

Якщо у вас є певний файл <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

3
@silvio: Ви можете створювати лише жорсткі посилання на файли , а не каталоги.
mklement0

@ mklement0: Ти маєш рацію!
Сільвіо

.І ..записи в каталогах жорсткі посилання. Ви можете сказати, скільки підкаталогів знаходиться в каталозі із кількості посилань .. Це все-таки суперечка, оскільки find -samefile .все одно не буде надруковано жодного subdir/..результату. find(принаймні, версія GNU), здається, важко кодується ігнорувати ..навіть з -noleaf.
Пітер Кордес

також, що ідея find-all-links є O(n^2)і запускається findодин раз для кожного члена набору файлів з твердими посиланнями. find ... -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separateбуде працювати, (16 недостатньо широке для десяткового представлення 2 ^ 63-1, тому коли ваша файлова система XFS є достатньо великою, щоб мати такі високі цифри, будьте уважні)
Пітер Кордес,

5

Є багато відповідей зі сценаріями, щоб знайти всі жорсткі посилання у файловій системі. Більшість з них займаються дурними речами, такими як запущені знахідки для сканування всієї файлової системи на -samefileнаявність множинного файлу EACH. Це божевілля; все, що вам потрібно, це сортувати за номером inode та друкувати дублікати.

Отримавши лише один прохід над файловою системою, щоб знайти та згрупувати всі набори файлів з жорсткою посиланням

find dirs   -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
    sort -n | uniq -w 42 --all-repeated=separate

Це набагато швидше, ніж інші відповіді на пошук декількох наборів файлів з твердими посиланнями.
find /foo -samefile /barвідмінно підходить для одного файлу.

  • -xdev: обмеження на одну файлову систему. Не потрібно суворо, оскільки ми також друкуємо FS-id для uniq
  • ! -type dвідхилити каталоги: записи .та ..записи означають, що вони завжди пов'язані.
  • -links +1 : посилання враховується строго > 1
  • -printf ...друкувати FS-id, номер inode та шлях. (З накладкою на фіксовану ширину стовпця, про яку ми можемо розповісти uniq.)
  • sort -n | uniq ... числове сортування та уніфікація на перших 42 стовпцях, розділяючи групи з порожнім рядком

Використання ! -type d -links +1означає, що вхід сорту такий же великий, як і кінцевий вихід uniq, тому ми не проводимо величезну кількість сортування рядків. Якщо ви не запустите його у підкаталозі, який містить лише один із набору жорстких посилань. У будь-якому випадку, це використовуватиме МНОГО менше часу процесора для переходу файлової системи, ніж будь-яке інше розміщене рішення.

вибірка вибірки:

...
            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 ?: відклеїти вихід з awkабо cut. uniqмає дуже обмежену підтримку вибору поля, тому я прокладаю висновок пошуку та використовую фіксовану ширину. 20chars є достатньо широким для максимально можливого числа вводу або пристрою (2 ^ 64-1 = 18446744073709551615). XFS вибирає номери inode залежно від того, на якому диску вони розміщені, а не з 0, тому великі файлові системи XFS можуть мати> 32-бітові числа inode, навіть якщо у них немає мільярдів файлів. В інших файлових системах можуть бути 20-значні цифри вводу, навіть якщо вони не є гігантськими.

TODO: сортування груп дублікатів за маршрутом. Сортувавши їх за точкою монтажу, тоді номер inode змішує речі разом, якщо у вас є декілька різних підкаталогів, у яких багато твердих посилань. (тобто групи дуп-груп йдуть разом, але вихід змішує їх).

Фінал sort -k 3буде сортувати рядки окремо, а не групи рядків як єдиний запис. Попередня обробка чимось для перетворення пари нових рядків у байт NUL і використання GNU sort --zero-terminated -k 3може зробити цю справу. trфункціонує лише на окремих символах, але не 2-> 1 або 1-> 2 шаблони. perlзробив би це (або просто проаналізував і впорядкував у програмі perl або awk). sedможе також спрацювати.


1
%Dідентифікатор файлової системи (вона є унікальним для поточної завантаження , а не файлові системи не umountед), тому наступний ще більш загальний характер : find directories.. -xdev ! -type d -links +1 -printf '%20i %20D %p\n' | sort -n | uniq -w 42 --all-repeated=separate. Це працює, поки жоден каталог не містить іншої директорії на рівні файлової системи, а також він переглядає все, що може бути жорсткопов'язаним (наприклад, пристрої або софтпосилання - так, програмні посилання можуть мати кількість посилань більше 1). Зауважимо, що це dev_tі ino_tстановить 64 біти на сьогодні. Це, ймовірно, буде тримати, поки у нас є 64-бітні системи.
Тіно

@Tino: чудовий сенс використання ! -type d, а не використання -type f. У мене навіть є декілька жорстких посилань на мою файлову систему з організації деяких колекцій файлів. Оновили свою відповідь вашою вдосконаленою версією (але я поставив fs-id першим, тож упорядкуйте сортування принаймні за групами файлової системи.)
Пітер Кордес

3

Це дещо зауваження до власної відповіді та сценарію Торокоро-Мачо, але воно, очевидно, не вміститься у поле для коментарів.


Перепишіть свій сценарій більш простими способами пошуку інформації, і, таким чином, набагато менше викликів обробки.

#!/bin/sh
xPATH=$(readlink -f -- "${1}")
for xFILE in "${xPATH}"/*; do
    [ -d "${xFILE}" ] && continue
    [ ! -r "${xFILE}" ] && printf '"%s" is not readable.\n' "${xFILE}" 1>&2 && continue
    nLINKS=$(stat -c%h "${xFILE}")
    if [ ${nLINKS} -gt 1 ]; then
        iNODE=$(stat -c%i "${xFILE}")
        xDEVICE=$(stat -c%m "${xFILE}")
        printf '\nItem: %s[%d] = %s\n' "${xDEVICE}" "${iNODE}" "${xFILE}";
        find "${xDEVICE}" -inum ${iNODE} -not -path "${xFILE}" -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 "$ {xFILE}") працює не у всіх системах (наприклад: stat (GNU coreutils) 6.12). Якщо сценарій виводить "Item:?" в передній частині кожного рядка, а потім замініть цей образливий рядок рядком, схожим на оригінальний сценарій, але з xITEM, перейменованим на xFILE: xDEVICE = $ (df "$ {xFILE}" | хвіст -1l | awk '{print $ 6} ')
kbulgrien

Якщо ви просто хочете, щоб групи жорстких посилань, а не повторювались з кожним членом як "головний", використовуйте find ... -xdev -type f -links +1 -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate. Це набагато швидше, оскільки він проходить лише один раз. Для декількох FSes одночасно, вам потрібно буде встановити номери inode за допомогою ідентифікатора FS. Можливо, зfind -exec stat... -printf ...
Пітер Кордес,

перетворив цю ідею у відповідь
Пітер Кордес,

2

На основі 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}"; IFS=$'\n';
xPATH="${1}";
xFILES="`ls -al ${xPATH}|egrep "^-"|awk '{print $9}'`";
for xFILE in ${xFILES[@]}; do
  xITEM="${xPATH}/${xFILE}";
  if [[ ! -r "${xITEM}" ]] ; then
    echo "Path: '${xITEM}' is not accessible! ";
  else
    nLINKS=$(ls -ld "${xITEM}" | awk '{print $2}')
    if [ ${nLINKS} -gt 1 ]; then
      iNODE=$(ls -id "${xITEM}" | awk '{print $1}' | head -1l)
      xDEVICE=$(df "${xITEM}" | tail -1l | awk '{print $6}')
      echo -e "\nItem: ${xDEVICE}[$iNODE] = ${xITEM}";
      find ${xDEVICE} -inum ${iNODE} 2>/dev/null|egrep -v "${xITEM}"|sed 's/^/   -> /';
    fi
  fi
done
IFS="${oIFS}"; echo "";

Я написав коментарі до цього сценарію як окрему відповідь.
Даніель Андерссон

1

Рішення GUI дійсно наближається до вашого питання:

Ви не можете перелічити фактично жорсткі файли з "ls", оскільки, як зазначали попередні коментатори, файл "імена" - це просто псевдоніми одних і тих же даних. Однак насправді існує інструмент GUI, який дійсно наближається до того, що ви хочете, - це відображення списку імен файлів, які вказують на ті самі дані (як жорсткі посилання) під Linux, воно називається FSLint. Опція, яку ви хочете, знаходиться в розділі "Сутички з іменами" -> зніміть "прапорець $ PATH" у Пошуку (XX) -> та виберіть "Псевдоніми" зі спадного поля після "за ..." у напрямку до верхньої середини.

FSLint дуже погано задокументований, але я виявив, що переконайтесь, що обмежене дерево каталогів у розділі "Шлях пошуку" встановлено прапорець "Повторити?" та вищезазначені параметри, перелік твердопов'язаних даних із шляхами та іменами, які "вказують" на ті самі дані, створюються після пошуку програми.


FSlint можна знайти на pixelbeat.org/fslint
mklement0

1

Ви можете налаштувати lsвиділення жорстких посилань за допомогою "псевдоніму", але, як зазначено раніше, немає способу показати "джерело" твердого посилання, тому я звертаюся .hardlinkза допомогою у цьому.

виділити жорсткі посилання

Додайте наступне десь у своєму .bashrc

alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.