я бегу
ln /a/A /b/B
Я хотел бы видеть в папке, a
где файл A указывает на ls
.
я бегу
ln /a/A /b/B
Я хотел бы видеть в папке, a
где файл A указывает на ls
.
Ответы:
Вы можете найти номер инода для вашего файла с помощью
ls -i
а также
ls -l
показывает количество ссылок (количество жестких ссылок на определенный индекс)
после того как вы нашли номер инода, вы можете искать все файлы с одинаковым инодом:
find . -inum NUM
покажет имена файлов для inode NUM в текущем каталоге (.)
На самом деле нет четко определенного ответа на ваш вопрос. В отличие от символических ссылок, жесткие ссылки неотличимы от «оригинального файла».
Записи каталога состоят из имени файла и указателя на индекс. Индод, в свою очередь, содержит метаданные файла и (указатели на) фактическое содержимое файла). Создание жесткой ссылки создает другое имя файла + ссылку на тот же индекс. Эти ссылки являются однонаправленными (по крайней мере, в типичных файловых системах) - индекс хранит только счетчик ссылок. Не существует внутреннего способа узнать, какое имя файла является «оригинальным».
Кстати, именно поэтому системный вызов «удалить» файл называется unlink
. Это просто удаляет жесткую ссылку. Индод, к которому прикреплены данные, удаляется только в том случае, если счетчик ссылок инода падает до 0.
Единственный способ найти другие ссылки на данный индекс - это провести тщательный поиск в файловой системе, проверяя, какие файлы ссылаются на рассматриваемый индекс. Вы можете использовать 'test A -ef B' из оболочки для выполнения этой проверки.
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 '{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
находясь в OS X Zsh. Мое текущее окно на экране закрывается.
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 достаточно велика, чтобы иметь столь высокие номера инодов, будьте внимательны)
Есть много ответов со скриптами, чтобы найти все жесткие ссылки в файловой системе. Большинство из них делают глупые вещи, такие как запуск find для сканирования всей файловой системы на -samefile
предмет КАЖДОГО многосвязного файла. Это безумие; все, что вам нужно, это отсортировать по номеру инода и распечатать дубликаты.
Только один проход по файловой системе, чтобы найти и сгруппировать все наборы жестко связанных файлов
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 в uniq на! -type d
отклонять каталоги: .
и ..
запись означает , что они всегда связаны между собой .-links +1
: количество ссылок строго > 1
-printf ...
выведите FS-id, номер индекса и путь. (С дополнением к фиксированной ширине столбца, о котором мы можем рассказать 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
имеет очень ограниченную поддержку выбора полей, поэтому я дополняю результаты поиска и использую фиксированную ширину. 20 символов достаточно широки для максимально возможного индекса или номера устройства (2 ^ 64-1 = 18446744073709551615). XFS выбирает номера инодов в зависимости от того, где на диске они расположены, а не от 0, поэтому большие файловые системы XFS могут иметь> 32-битные номера инодов, даже если у них нет миллиардов файлов. Другие файловые системы могут иметь 20-значные номера инодов, даже если они не гигантские.
TODO: сортировка групп дубликатов по пути. Сортировка их по точке монтирования, а затем по номеру инода смешивает вещи, если у вас есть пара разных подкаталогов, которые имеют много жестких ссылок. (то есть группы дуп-групп объединяются, но вывод смешивает их).
Финал 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
. Это НАМНОГО быстрее, так как проходит только один раз. Для нескольких FS, вам нужно префикс номера 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 "";
Решение с графическим интерфейсом действительно близко к вашему вопросу:
Вы не можете перечислить фактические жестко связанные файлы из «ls», потому что, как указывали предыдущие комментаторы, «имена» файлов являются просто псевдонимами к тем же данным. Тем не менее, на самом деле есть инструмент с графическим интерфейсом, который очень близок к тому, что вы хотите, который отображает список путей имен файлов, которые указывают на те же данные (как жесткие ссылки) в Linux, он называется FSLint. Требуемая опция находится в разделе «Конфликты имен» -> снимите флажок «$ PATH» в разделе «Поиск (XX) ->» и выберите «Псевдонимы» в раскрывающемся списке после «для ...» по направлению к верхней середине.
FSLint очень плохо документирован, но я обнаружил, что удостоверился, что ограниченное дерево каталогов в разделе «Путь поиска» с установленным флажком «Recurse?» и вышеупомянутые опции, список жестко связанных данных с путями и именами, которые «указывают» на одни и те же данные, создаются после поиска программы.
Вы можете настроить 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. Все, что они делают, это пересчитывают индекс, чтобы он мог быть удален, когда фамилия для негоunlink(2)ed
. (Это «количество ссылок» вls
выходных данных).