Определение, является ли файл жесткой ссылкой или символической ссылкой?

52

Я создаю сценарий оболочки, который берет имя файла / путь к файлу и определяет, является ли файл символической ссылкой или жесткой ссылкой.

Единственное, я не знаю, как узнать, являются ли они жесткой связью. Я создал 2 файла, один из которых является жесткой ссылкой, а другой - символической ссылкой для использования в качестве тестового файла. Но как мне определить, является ли файл жесткой ссылкой или символическим в сценарии оболочки?

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

к-Rocker
источник
16
Что вы подразумеваете под жесткой ссылкой? Все файлы являются жесткими ссылками.
Тердон
1
@terdon ln /foo/bar/ /foo/bar2делает жесткую ссылку, в то время как ln -s /foo/bar /foo/bar2делает символическую ссылку, вот что он имеет в виду?
DisplayName
14
@DisplayName да, но все файлы являются жесткими ссылками на их индекс. Вот как работают файловые системы Linux. В вашем примере bar2и barобе жесткие ссылки, просто указывающие на один и тот же индекс.
Terdon
10
@DisplayName да, это жесткие ссылки на другие иноды . Здесь нет противоречия. Файл - это ссылка на индекс. Это определение файла. В вашем случае у вас есть эти ссылки в разных местах, но это не меняет основную структуру данных. Моя точка зрения заключается в том, что оба barи bar2одинаково важны. Одна не является ссылкой на другую, они обе являются ссылками, но указывают на один и тот же индекс.
Terdon
3
@ Скотт нет, я говорю, что обычные файлы - это жесткие ссылки, и созданные жесткие ссылки lnничем не отличаются от обычных файлов.
Terdon

Ответы:

42

Ответ Джим объясняет , как проверить на линке: с помощью test«s -Lтест.

Но тестирование на «жесткую ссылку», строго говоря, не то, что вы хотите. Жесткие ссылки работают из-за того, как Unix обрабатывает файлы: каждый файл представлен одним индексом. Тогда один инод имеет ноль или более имен или записей каталога или, технически, жестких ссылок (то, что вы называете «файлом»).

К счастью, statкоманда, где она доступна, может сказать вам, сколько имен у inode.

Итак, вы ищете что-то вроде этого (здесь предполагается реализация GNU или busybox stat):

if [ "$(stat -c %h -- "$file")" -gt 1 ]; then
    echo "File has more than one name."
fi

Этот -c '%h'бит говорит statпросто выводить количество жестких ссылок на индекс, т. Е. Количество имен в файле. -gt 1затем проверяет, больше ли это 1.

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

derobert
источник
Хорошо, просто для ясности, я могу вывести количество жестких ссылок, которые имеет файл, используя команду stat, и если его значение больше 1, то у него есть другой файл, связанный где-то в разделе.
K-Rocker
@ K-Rocker Да. Тогда у него есть второе имя где-то в разделе.
Дероберт
1
На OS X или * BSD это так stat -f %l /path/to/file. Вы также можете использовать, gstat -c %h /path/to/fileесли у вас установлены GNU coreutils без имен по умолчанию (с Homebrew на OS X).
GDP2
29

Пример:

$ touch f1
$ ln f1 f2
$ ln f1 f3
$ ln -s f1 s1
$ ln -s f2 s2
$ ln -s ./././f3 s3
$ ln -s s3 s4
$ ln s4 s5
$ ls -li
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802345 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s1 -> f1
10802346 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s2 -> f2
10802347 lrwxrwxrwx 1 stephane stephane 8 Nov 12 19:56 s3 -> ./././f3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s4 -> s3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s5 -> s3

В f1, f2и f3запись каталога и тот же файл (тот же индексный дескриптор: 10802124, вы заметите , количество ссылок является 3). Это жесткие ссылки на один и тот же обычный файл.

s4а s5также тот же файл (10802384). Они имеют тип symlink , а не обычные . Они указывают на путь, здесь s3. Поскольку s4и s5являются записями одного и того же каталога, этот относительный путь s3указывает на один и тот же файл (файл с inod 10802347) для обоих.

Если вы делаете ls -Ll, то запрашиваете информацию о файле после разрешения символических ссылок:

$ ls -lLi
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s4
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s5

Вы найдете, что они все разрешают к тому же файлу (10802124).

Вы можете проверить, является ли файл символической ссылкой [ -L file ]. Точно так же вы можете проверить, является ли файл обычным файлом [ -f file ], но в этом случае проверка выполняется после разрешения символических ссылок.

Жесткие ссылки - это не тип файла, это просто разные имена для файла (любого типа).

Стефан Шазелас
источник
19

Использование -hи -Lоператоры testкоманды:

-h file 
true if file is a symbolic link

-L file 
true if file is a symbolic link

http://www.mkssoftware.com/docs/man1/test.1.asp

Согласно этому потоку SO , они ведут себя одинаково, но -Lпредпочтительнее.

Jimm-сл
источник
хорошо, круто, а как насчет жестких ссылок? Я проверил шаг, но ничего о жестких ссылках. Если -L возвращает false, означает ли это жесткую ссылку? или просто обычный файл?
K-Rocker
1
Жесткие ссылки делят то же самое inode. Кроме того, программные ссылки показывают lв начале ls -lвывода ... Я думаю, что вы можете объединить эти правила в сценарии, а также [[ -L file ]]проверить, является ли данный файл мягким или жестким .
Джимм-кл
Хорошо, также, как я могу найти целевой раздел символической ссылки?
K-Rocker
3

Здесь много совершенно правильных ответов, но я не думаю, что кто-то действительно справился с первоначальным заблуждением. Исходный вопрос в основном заключается в том, что «когда я делаю символическую ссылку, впоследствии ее легко идентифицировать. Но я не могу понять, как определить жесткую ссылку». И да, ответы в основном сводятся к «вы не можете» и более или менее объясняют почему, но никто, кажется, не признал, что, действительно, это сбивает с толку и странно.

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

Действительно очень короткий ответ заключается в том, что жесткая ссылка на самом деле вовсе не ссылка, а не символическая ссылка. Это новая запись в структуре каталогов, которая указывает на тот же набор байтов, что и оригинальная запись каталога, и после того, как вы ее создали, она так же «реальна» и легитимна, как и первая. Каждый «нормальный» файл на вашем диске имеет хотя бы одну жесткую ссылку; без этого вы бы не увидели ни в одномкаталог, и не сможет ссылаться на него или использовать его. Поэтому, если у вас есть файл Fred.txt и вы жестко связываете с ним Wilma.txt и Barney.txt, все три имени (и записи каталога) ссылаются на один и тот же файл, и все они одинаково действительны. Для ОС нет никакого способа сказать, что одна из записей была создана, когда вы нажали «сохранить» в текстовом редакторе, а другие были сделаны с помощью команды «ln».

ОС действительно должны отслеживать , сколько различных записей , указывающих на тот же файл, хотя. Если вы удалите Wilma.txt, не удивительно, что вы не освободите место на диске. Но если вы удалите Fred.txt («оригинальный» файл), вы все равно не освободите место на диске, потому что данные на диске, который был известен как Fred.txt, по-прежнему также Barney.txt. Только когда вы удалите все записи каталога, ОС освободит место, которое занимали сами данные.

Если бы Barney.txt был символической ссылкой, то удаление Fred.txt освободило бы пространство, а Barney.txt теперь было бы неработающей ссылкой. Кроме того, если вы переместите или переименуете файл, на который указывает символическая ссылка, вы нарушите эту ссылку. Но вы можете перемещать или переименовывать жестко связанный файл, как вам угодно, не нарушая другие записи каталога, которые указывают на этот файл / данные, поскольку все они являются записями каталога, которые ссылаются на один и тот же блок данных на диске (с помощью индекс # этих данных).

[Прошло два года, и это последнее немного смутило меня , так что я думаю, что уточнить. Если вы наберете «mv ./Wilma.txt ../elsewhere/Betty.txt», то, похоже, вы перемещаете файл, но на самом деле это не так. Что вы действительно делаете, так это удаляете элемент строки из списка каталогов вашего текущего каталога, тот, который говорит, что «имя« Wilma.txt »связано с данными, которые можно найти с помощью inode ###### #, "и добавление новой позиции в список каталогов каталога ../elsewhere, где говорится, что" имя 'Betty.txt' связано с данными, которые можно найти через inode ####### ". Вот почему вы можете «переместить» файл размером 2 гигабайта так же быстро, как файл размером 2 килобайта, при условии, что вы перемещаете их в другое место на том же диске.]

Поскольку ОС должна отслеживать, сколько разных записей каталога указывают на один и тот же кусок данных, вы можете определить, была ли жесткая ссылка на конкретный файл, даже если вы не можете точно сказать, является ли эта запись каталога Вы смотрите на «оригинал» или нет. Одним из способов является команда «ls», а именно «ls -l» (это строчная буква L после тире)

Заимствовать более ранний пример ....

 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1

Первая буква - тире, так что это не каталог или что-то еще экзотическое, это обычный файл. Но если бы оно было действительно обычным, это число после части rwx-ish было бы «1», как, например, «есть одна запись каталога, указывающая на этот блок данных». Но это часть демонстрации жестких ссылок, поэтому вместо этого написано «3».

Обратите внимание, что это может привести к странному и таинственному поведению (то есть, если вы не обернулись вокруг жестких ссылок). Если вы откроете Fred.txt в текстовом редакторе и внесете некоторые изменения, увидите ли вы те же изменения в Wilma.txt и Barney.txt? Может быть. Вероятно. Если ваш текстовый редактор сохраняет изменения, открыв исходный файл и записав в него изменения, то да, все три имени будут по-прежнему указывать на один и тот же (недавно измененный) текст. Но если ваш текстовый редактор создает новый файл (Fred-new-temp.txt), записывает в него измененную версию, затем удаляет Fred.txt, а затем переименовывает Fred-new-temp.txt в Fred.txt, Вильма и Барни по-прежнему указывать на оригинальную версию, а не на новую измененную версию. Если вы не понимаете жестких ссылок, это может привести вас в бешенство. :) [Ладно, я лично не знаю ни одноготекстовые редакторы, которые будут выполнять функцию new-file / rename, но я знаю много других программ, которые делают именно это, так что будьте начеку.]

И последнее замечание: одна из вещей, которую проверяет fsck (проверка файловой системы), состоит в том, есть ли на вашем диске блоки данных, на которые почему-то больше не ссылаются какие-либо записи каталога. Иногда что-то идет не так, и единственная запись в каталоге, которая указывает на индекс, удаляется, но само пространство диска не помечается как «доступное». Таким образом, одна из задач fsck - сопоставить все выделенное пространство со всеми записями каталога, чтобы убедиться, что нет никаких файлов, на которые нет ссылок. Если он находит некоторые, он создает новые записи каталога и помещает их в «lost + found».

Snarke
источник
Просто интересно, что это за «другие программы, которые делают именно это»?
phk
@phk Не знаю, о чем конкретно он думает, но это достаточно распространенный подход для выполнения действий, которые могут занять много времени и в случае неудачи оставят вас в неопределенном состоянии. Например, если вы пытаетесь загрузить файл с удаленного сервера и знаете, что существует вероятность истечения времени ожидания сервера, тогда одним из подходов будет загрузка всего содержимого во временный файл. Таким образом, если что-то пойдет не так с загрузкой, у вас останется оригинальный файл.
cwallenpoole
Единственная программа, которую я знаю наверняка, - FreeHand, потому что, если / когда она падает во время сохранения, остается временный файл, а не искаженный исходный файл. Но я видел, что другие программы тоже это делают; Я просто не могу дать вам конкретные примеры в настоящее время.
Snarke
2

Вы можете использовать readlink FILE; echo $?. Возвращает 1, когда это жесткая ссылка, и 0, когда это символическая ссылка.

Со страницы руководства: «Когда вызывается как ссылка для чтения, печатается только цель символической ссылки. Если данный аргумент не является символической ссылкой, readlink ничего не напечатает и завершится с ошибкой».

user2103720
источник