я біжу
ln /a/A /b/B
Я хотів би бачити в папці , a
де знаходяться точки файла A до шляху ls
.
я біжу
ln /a/A /b/B
Я хотів би бачити в папці , a
де знаходяться точки файла A до шляху ls
.
Відповіді:
Ви можете знайти номер inode для вашого файлу за допомогою
ls -i
і
ls -l
показує кількість посилань (кількість жорстких посилань на певний inode)
знайшовши номер inode, ви можете шукати всі файли з однаковим inode:
find . -inum NUM
покаже назви файлів для inode NUM у поточному режимі (.)
Насправді немає чітко визначеної відповіді на ваше запитання. На відміну від символьних посилань, жорсткі посилання не відрізняються від "оригінального файлу".
Записи каталогів складаються з імені файлу та вказівника на індекс. Inode, в свою чергу, містить метадані файлу та (вказує на) фактичний вміст файлу). Створення жорсткого посилання створює інше ім'я файлу + посилання на той самий вхід. Ці посилання є односпрямованими (як мінімум у типових файлових системах) - inode зберігає лише кількість посилань. Немає внутрішнього способу дізнатися, яке саме "оригінальне" ім'я файлу.
До речі, саме тому викликається системний виклик для "видалення" файлу unlink
. Це просто видаляє жорстке посилання. Вкладені дані inode видаляються лише в тому випадку, якщо посилальне число inode падає до 0.
Єдиний спосіб знайти інші посилання на даний інод - це вичерпний пошук файлової системи, перевіряючи, які файли відносяться до відповідної індеди. Ви можете використовувати 'test A -ef B' з оболонки для здійснення цієї перевірки.
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
. ./findhardlinks.bash
перебуваючи в Zsh OS X. Моє поточне вікно в екрані закривається.
INUM=$(stat -c %i $1)
. Також NUM_LINKS=$(stat -c %h $1)
. Перегляньте man stat
додаткові змінні формату, які ви можете використовувати.
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
inode
що в свою чергу вказує на вміст диска.
Як щодо наступного простішого? (Пізніший варіант може замінити довгі сценарії вище!)
Якщо у вас є певний файл <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
тому що файл теж може бути каталогом.
.
І ..
записи в каталогах жорсткі посилання. Ви можете сказати, скільки підкаталогів знаходиться в каталозі із кількості посилань .
. Це все-таки суперечка, оскільки find -samefile .
все одно не буде надруковано жодного subdir/..
результату. find
(принаймні, версія GNU), здається, важко кодується ігнорувати ..
навіть з -noleaf
.
O(n^2)
і запускається find
один раз для кожного члена набору файлів з твердими посиланнями. find ... -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate
буде працювати, (16 недостатньо широке для десяткового представлення 2 ^ 63-1, тому коли ваша файлова система XFS є достатньо великою, щоб мати такі високі цифри, будьте уважні)
Є багато відповідей зі сценаріями, щоб знайти всі жорсткі посилання у файловій системі. Більшість з них займаються дурними речами, такими як запущені знахідки для сканування всієї файлової системи на -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
може також спрацювати.
%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-бітні системи.
! -type d
, а не використання -type f
. У мене навіть є декілька жорстких посилань на мою файлову систему з організації деяких колекцій файлів. Оновили свою відповідь вашою вдосконаленою версією (але я поставив fs-id першим, тож упорядкуйте сортування принаймні за групами файлової системи.)
Це дещо зауваження до власної відповіді та сценарію Торокоро-Мачо, але воно, очевидно, не вміститься у поле для коментарів.
Перепишіть свій сценарій більш простими способами пошуку інформації, і, таким чином, набагато менше викликів обробки.
#!/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
.
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 ...
На основі 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 "";
Рішення GUI дійсно наближається до вашого питання:
Ви не можете перелічити фактично жорсткі файли з "ls", оскільки, як зазначали попередні коментатори, файл "імена" - це просто псевдоніми одних і тих же даних. Однак насправді існує інструмент GUI, який дійсно наближається до того, що ви хочете, - це відображення списку імен файлів, які вказують на ті самі дані (як жорсткі посилання) під Linux, воно називається FSLint. Опція, яку ви хочете, знаходиться в розділі "Сутички з іменами" -> зніміть "прапорець $ PATH" у Пошуку (XX) -> та виберіть "Псевдоніми" зі спадного поля після "за ..." у напрямку до верхньої середини.
FSLint дуже погано задокументований, але я виявив, що переконайтесь, що обмежене дерево каталогів у розділі "Шлях пошуку" встановлено прапорець "Повторити?" та вищезазначені параметри, перелік твердопов'язаних даних із шляхами та іменами, які "вказують" на ті самі дані, створюються після пошуку програми.
Ви можете налаштувати ls
виділення жорстких посилань за допомогою "псевдоніму", але, як зазначено раніше, немає способу показати "джерело" твердого посилання, тому я звертаюся .hardlink
за допомогою у цьому.
Додайте наступне десь у своєму .bashrc
alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
link(2)
системного дзвінка немає сенсу, у якому один є оригіналом, а хто - посиланням. Ось чому, як вказують відповіді, єдиний спосіб знайти всі посилання - цеfind / -samefile /a/A
. Оскільки один запис каталогу для inode не "знає про" інші записи каталогів для того ж inode. Все, що вони роблять, - це перерахунок inode, щоб його можна було видалити, коли прізвище єunlink(2)ed
. (Це "кількість посилань" уls
виході).