it-swarm-ru.tech

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

Я бегу

ln /a/A /b/B

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

88
Léo Léopold Hertz 준영

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

ls -i

а также

ls -l

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

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

find . -inum NUM

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

162
zzr

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

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

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

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

59
Laurence Gonsalves

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

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

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

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

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

findhardlinks ~/jquery.js

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

[email protected]:~# ./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
33
user53528
ls -l

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

[email protected]    2    [username]    [group]    [timestamp]     HardLink
[email protected]    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data
24
eyelidlessness

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

Если у вас есть определенный файл <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 {} \; 
10
Loves Probability

Есть много ответов со скриптами, чтобы найти все жесткие ссылки в файловой системе. Большинство из них делают глупые вещи, такие как запуск find для сканирования всей файловой системы на наличие -samefile для КАЖДОГО многосвязного файла. Это безумие; все, что вам нужно, это отсортировать по номеру инода и распечатать дубликаты.

find directories.. -xdev ! -type d -links +1 -printf '%20D %20i %p\n' | sort -n | uniq -w 42 --all-repeated=separate (Спасибо @Tino за настройку моей исходной команды для поддержки FS-идентификатора (%D) и для обработки всех типов файлов, не относящихся к каталогам, а не только обычных файлов. Это найдет ваши многосвязные символические ссылки, каналы и т. д.)

Использование ! -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 ?: распаковать вывод. 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 также может работать.

4
Peter Cordes

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


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

#!/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. Это сохранит вызовы процессов, что почти всегда значительно повышает производительность в трудолюбивых сценариях.

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

3
Daniel Andersson

Основанный на сценарии 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 "";
2
Torocoro-Macho

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

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

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

1
Charles

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

 highlight hardlinks

Добавьте следующее где-нибудь в свой .bashrc

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