Как вы можете увидеть реальную жесткую ссылку на ls?
Я запускаю
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 в текущем каталоге (.)
На ваш вопрос нет четкого ответа. В отличие от сим-ссылок, жесткие ссылки неотличимы от “исходного файла”. Записи в каталоге
состоят из имени файла и указателя на вход. Внутренний код, в свою очередь, содержит метаданные файла и (указатель на) фактическое содержимое файла). При создании жесткой ссылки создается другое имя файла + ссылка на тот же вход. Эти ссылки однонаправленные (по крайней мере, в типичных файловых системах) – в иноде хранится только счетчик ссылок. Нет внутреннего способа узнать, что является “оригинальным” именем файла.
Кстати, поэтому системный вызов для “удаления” файла называется unlink
. Он просто удаляет жесткую ссылку. Входящие данные удаляются только в том случае, если счетчик ссылок на входе падает до 0.
Единственный способ найти остальные ссылки на данный вход - исчерпывающий поиск по файловой системе, проверяющей, какие файлы относятся к данному входу. Вы можете использовать ‘test A -ef B’ из оболочки для выполнения этой проверки.
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
Как насчет следующего проще? (Latter может заменить длинные сценарии выше!)
Если у вас есть конкретный файл <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 {} \;
Есть много ответов со скриптами, чтобы найти все жесткие ссылки в файловой системе. Большинство из них делают глупые вещи, такие как запуск find для сканирования всей файловой системы на -samefile
для EACH-файлов с многосшифрованными ссылками. Это безумие; все, что вам нужно, это сортировать по номеру и распечатывать дубликаты. 0x2 и 0x2 и С одним проходом по файловой системе, чтобы найти и сгруппировать все наборы жестко связанных файлов 0x2 и 0x2 и 0x1 и 0x2 и 0x2 и Это гораздо быстрее, чем другие ответы для поиска нескольких наборов жестко связанных файлов.
find /foo -samefile /bar
отлично подходит только для одного файла.
-xdev
: ограничение для одной файловой системы. Необязательно, поскольку мы также печатаем FS-id в uniq в каталогах ! -type d
: записи .
и ..
означают, что они всегда связаны друг с другом. -links +1
: счетчик ссылок строго > 1
-printf ...
печатает FS-id, номер кода и путь. (С подкладкой на фиксированную ширину столбцов, о которой мы можем сказать uniq
.) sort -n | uniq ...
числовая сортировка и унификация на первых 42 столбцах, разделение групп пустой строкой Использование ! -type d -links +1
означает, что входные данные сортировки только столь же велики, как и конечный вывод uniq, поэтому мы не выполняем огромную сортировку строк. Если только вы не запустите его в подкаталоге, который содержит только один из набора жестких ссылок. В любом случае, при этом будет использовано намного меньше процессорного времени на обход файловой системы, чем при любом другом размещенном решении. Вывод
сэмплов:
find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
sort -n | uniq -w 42 --all-repeated=separate
TODO?: un-pad вывод с awk
или cut
. uniq
имеет очень ограниченную поддержку выбора поля, поэтому я забиваю выходной сигнал и использую фиксированную ширину. 20chars достаточно широки для максимально возможного числа входов или устройств (2^64-1 = 18446744073709551615). XFS выбирает номера кодов в зависимости от того, где на диске они распределены, а не от 0, так что большие файловые системы XFS могут иметь >32-битные номера кодов, даже если у них нет миллиардов файлов. Другие файловые системы могут иметь 20-значные номера, даже если они не гигантские.
TODO: сортируйте группы дубликатов по пути. Если они отсортированы по точке монтирования, то номер inode смешивает вещи вместе, если у вас есть пара разных подкаталогов, которые имеют много жестких ссылок. (т.е. группы дубликатов идут вместе, но на выходе они смешиваются). Окончательные
Окончательные sort -k 3
сортируют строки отдельно, а не группы строк как одну запись. Препроцессирование с помощью чего-нибудь, чтобы превратить пару новых строк в NUL-байт, и применение GNU sort --zero-terminated -k 3
могло бы выполнить эту хитрость. tr
работает только с одиночными символами, а не с шаблонами 2->1 или 1->2. perl
мог бы это сделать (или просто разобрать и отсортировать в perl или awk). sed
может также работать.
Это в некотором роде комментарий к собственному ответу и скрипту Torocoro-Macho, но он явно не поместится в поле для комментариев.
Переписать скрипт с более простыми способами поиска информации, и, таким образом, намного меньше ссылок на процесс.
#!/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
, согласован в all системах.
stat
может сэкономить вам много логики в этом случае.
GNU find
является мощным.
Ваши вызовы head
и tail
могли быть обработаны непосредственно в awk
с помощью, например, команды exit
и/или выбора в переменной NR
. Это позволило бы сэкономить вызовы процесса, что почти всегда значительно улучшает производительность в трудных скриптах.
Ваши egrep
с тем же успехом могли бы быть только grep
.
Основываясь на сценарии 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 "";
Решение с графическим интерфейсом очень близко к вашему вопросу:
Вы не можете перечислить фактические жестко связанные файлы из “ls”, потому что, как указывали предыдущие комментаторы, “имена” файлов - это просто псевдонимы к одним и тем же данным. Однако, на самом деле есть инструмент с графическим интерфейсом, который очень близок к тому, что вы хотите, и который показывает список путей с именами файлов, которые указывают на те же самые данные (как жесткие ссылки) под linux, он называется FSLint. Опция, которую вы хотите, находится под “Name clashes” -> снимите флажок “check box $PATH” в Search (XX) -> и выберите “Aliases” (Псевдонимы) из выпадающего списка после “for…” (для…) в направлении верхнего среднего уровня.
FSLint очень плохо документирован, но я обнаружил, что, убедившись в том, что ограниченное дерево каталогов под “Search path” с флажком “Recurse?” и вышеупомянутыми опциями, после поиска программы формируется список жестко привязанных данных с путями и именами, которые “указывают” на те же данные.
Вы можете настроить ls
на подсветку жестких ссылок с помощью ‘псевдонима’, но, как уже говорилось, невозможно показать ‘источник’ жесткой связи, поэтому я добавляю .hardlink
, чтобы помочь с этим.
Добавьте следующее где-нибудь в ваши .bashrc
alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'