Два файла жестко связаны?

27

Как я могу сказать, что два файла жестко связаны из командной строки? например, что-то связать это:

$ ls
fileA fileB fileC

$ is-hardlinked fileA fileB
yes

$ is-hardlinked fileA fileC
no
Винсент Шейб
источник

Ответы:

37

В большинстве файловых систем¹ файл однозначно определяется номером его инода , поэтому все, что вам нужно, это проверить, имеют ли два файла одинаковый номер инода и находятся ли они в одной файловой системе.

У Ash, ksh, bash и zsh есть конструкция, которая проверяет вас: оператор равенства файлов -ef.

[ fileA -ef fileB ] && ! [ fileA -ef fileC ]

Для более сложных случаев ls -i /path/to/fileперечисляет номер инода файла. df -P /path/to/fileпоказывает, в какой файловой системе находится файл (если два файла находятся в одном каталоге, они находятся в одной файловой системе). Если в вашей системе есть statкоманда, возможно, она отображает номера inode и файловой системы ( statзависит от системы, проверьте документацию). Если вы хотите быстро взглянуть на жесткие ссылки внутри каталога, попробуйте ls -i | sort(возможно, по каналу awk ).

¹ Все нативные файловые системы Unix и некоторые другие, такие как NTFS, но, возможно, не такие экзотические, как CramFS.

Жиль "ТАК - перестань быть злым"
источник
И определенно не на чем-нибудь основанном на FAT, где он будет обнаружен как «перекрестно связанный» файл.
Игнасио Васкес-Абрамс
4
Обратите внимание, что fileA -ef fileBтакже возвращается 0(успех), если fileAявляется символической fileBссылкой, или наоборот, или они оба ссылаются на один и тот же файл.
Янмезен
как на самом деле запустить команду, которую вы предложили? Я попробовал [.bashrc -ef .bash / .bashrc] и варианты этого, но это не сработало.
Чарли Паркер
@CharlieParker [ .bashrc -ef .bash/.bashrc ]правильный. Без контекста, конечно, я понятия не имею, почему это «на самом деле не работает» - вы могли бы сравнивать неправильные файлы, вы могли бы не проверять результат правильно, вы могли бы использовать оболочку без -ef
Жиль "ТАК - перестань быть злым"
2
@CharlieParker Команда на самом деле [и является синонимом test. Но man [или man testдаст вам страницу руководства по внешней команде, в то время как практически в каждой оболочке есть встроенная команда с немного отличающимися параметрами, поэтому вам нужно найти ее в руководстве по вашей оболочке.
Жиль "ТАК - перестань быть злым"
4
function is-hardlinked() {
    r=yes
    [ "`stat -c '%i' $1`" != "`stat -c '%i' $2`" ] && r=no
    echo $r
}
х-полосная
источник
6
Обратите внимание, что это может быть ложным срабатыванием, если два файла находятся в разных файловых системах, но имеют одинаковый индекс. Вам также необходимо проверить номер устройства ( stat -c %d). И если вы работаете в Linux (учитывая вашу statкоманду), ваша оболочка [ fileA -ef fileB ]должна делать все это напрямую. Кроме того, ваша команда произвольно разрывается с именами файлов, содержащими пробелы или \[?*, или начинается с -: всегда ставьте двойные кавычки вокруг команды susbtitutions ( "$(stat -c %i -- "$1")").
Жиль "ТАК - перестань быть злым"
1
Зачем вам использовать кучу громоздких, но переносимых конструкций, а затем совершенно непереносимое functionключевое слово с именем функции, которое (из-за наличия тире) нарушает соглашения POSIX по разрешенным именам?
Чарльз Даффи
Вы забыли процитировать $1и $2. Вы можете также захотеть использовать $()синтаксис вместо обратных кавычек, потому что квадратные скобки проясняют, где начинается команда и где она заканчивается, а вложение проще.
Йош
3

Как следует из первого постера, вы можете написать скрипт на основе чего-то подобного в Linux:

stat -c '%i' fileA fileB fileC
Не сейчас
источник
4
Этого недостаточно: вы получите одинаковое число для двух файлов, если они находятся в разных файловых системах, но имеют один и тот же индекс. Вам также необходимо проверить номер устройства ( stat -c %d). И если вы работаете в Linux (учитывая вашу statкоманду), ваша оболочка [ fileA -ef fileB ]должна делать все это напрямую.
Жиль "ТАК - перестань быть злым"
0

С GNU find(1)версии 4.2.11 или новее вы также можете использовать это:

if [ "yes" = "$(find fileA -samefile fileB -exec echo yes \;)" ]; then
    echo yes
else
    echo no
fi

Если fileAэто тот же файл, что и fileBтогда, findбудет напечатано «да», и условие станет истинным.

В отличие от использования оператора равенства файлов, -efэто порождает новый процесс.

josch
источник