web-dev-qa-db-ja.com

ファイルがハードリンクかシンボリックリンクかを判断しますか?

ファイルへのファイル名/パスを取得し、ファイルがシンボリックリンクかハードリンクかを判断するシェルスクリプトを作成しています。

唯一のことは、それらがハードリンクであるかどうかを確認する方法がわかりません。テストファイルとして使用するために、ハードリンクとシンボリックリンクの2つのファイルを作成しました。しかし、ファイルがシェルスクリプト内のハードリンクまたはシンボリックであるかどうかをどのように判断しますか?

また、シンボリックリンクの宛先パーティションをどのように見つけますか?では、別のパーティションにリンクしているファイルがあるとしましょう。その元のファイルへのパスを見つけるにはどうすればよいでしょうか。

54
k-Rocker

ジムの答えは、シンボリックリンクをテストする方法を説明しています:test-Lテストを使用します。

しかし、「ハードリンク」のテストは、厳密には、あなたが望んでいることではありません。 Unixがファイルを処理する方法により、ハードリンクは機能します。各ファイルは単一のiノードによって表されます。その場合、単一のiノードには0個以上のnamesまたはdirectory entriesまたは技術的にはhard links(「ファイル」と呼んでいるもの)があります。 。

ありがたいことに、statコマンドを使用すると、iノードの名前がいくつあるかがわかります。

だからあなたはこのようなものを探しています(ここではGNUまたはstatのbusybox実装を想定しています):

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

-c '%h'ビットは、statにiノードへのハードリンクの数、つまりファイルが持つ名前の数を出力するように指示します。 -gt 1は、それが1より大きいかどうかを確認します。

他のファイルと同様に、シンボリックリンクも複数のディレクトリにリンクできるため、1つのシンボリックリンクに複数のハードリンクを設定できることに注意してください。

44
derobert

例:

$ 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

f1f2、およびf3ディレクトリエントリは同じファイルです(同じiノード:10802124。linksの数は3です)。それらは同じregularファイルへのハードリンクです。

s4s5も同じファイルです(10802384)。タイプはsymlinkであり、regularではありません。それらはパスを指します。ここではs3です。 s4s5は同じディレクトリのエントリであるため、その相対パス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)にresolveで見つかります。

ファイルが[ -L file ]のシンボリックリンクかどうかを確認できます。同様に、ファイルが[ -f file ]の通常のファイルであるかどうかをテストできますが、その場合、チェックはシンボリックリンクを解決した後に行われます。

ハードリンクはファイルのタイプではなく、ファイルの(任意のタイプの)異なる名前です。

29

testコマンドの-hおよび-L演算子を使用する:

-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

this SO thread によると、これらは同じ動作をしますが、-Lが推奨されます。

19
jimm-cl

ここにはかなり正しい答えがたくさんありますが、元の誤解に実際に取り組んだ人はいないと思います。元の質問は基本的に「シンボリックリンクを作成すると、後で簡単に識別できます。しかし、ハードリンクを識別する方法がわかりません。」そして、はい、基本的には答えは「できない」に要約され、多かれ少なかれその理由を説明しますが、実際にはそれを認めていないようですIS混乱していて奇妙です。

これらすべてを読んでいて、何が起こっているのかを理解していれば、それで問題ありません。あなたは私の少しを読む必要はありません。それでも混乱している場合は、続けてください。

本当に短い答えは、ハードリンクは実際にはリンクではなく、シンボリックリンクではないということです。これは、元のディレクトリエントリと同じバイト数を指すディレクトリ構造の新しいエントリであり、一度作成すると、最初のエントリと同じように「本物」で正当なものになります。 すべてドライブ上の「通常の」ファイルには、少なくとも1つのハードリンクがあります。これがないと、anyディレクトリに表示されず、参照したり使用したりできません。したがって、ファイルFred.txtがあり、そのファイルにWilma.txtとBarney.txtをハードリンクする場合、3つの名前(およびディレクトリエントリ)はすべて同じファイルを参照し、それらはすべて等しく有効です。テキストエディタで「保存」を押したときにエントリの1つが作成され、その他は「ln」コマンドで作成されたことをOSが認識する方法はありません。

ただし、OSdoesは、同じファイルを指している異なるエントリの数を追跡する必要があります。 Wilma.txtを削除しても、ドライブのスペースが解放されないのは当然です。ただし、Fred.txt(「元の」ファイル)を削除しても、Fred.txtと呼ばれていたドライブ上のデータは引き続きBarney.txtであるため、ドライブ上の領域を解放することはできません。 OSは、ディレクトリエントリのallを削除した場合のみ、データ自体が占有していたスペースの割り当てを解除します。

Barney.txtがシンボリックリンクであった場合、Fred.txtを削除するとwouldスペースの割り当てが解除され、Barney.txtは壊れます。リンク。また、シンボリックリンクを指しているファイルを移動または名前変更すると、リンクが解除されます。ただし、ハードリンクされたファイルは、そのファイル/データを指す他のディレクトリエントリを壊すことなく、必要に応じて移動または名前を変更できます。これらはすべて、ドライブ上の同じデータブロックを参照するディレクトリエントリであるためです(そのデータのiノード番号)。

[2年後、最後の少し混乱してなので、はっきりさせておきます。 「mv ./Wilma.txt ../elsewhere/Betty.txt」と入力すると、ファイルを移動しているように見えますが、実際はそうではありません。実際に行っているのは、現在のディレクトリのディレクトリリストから行項目を削除することです。「名前「Wilma.txt」は、inode ######を使用して見つけることができるデータに関連付けられています」 #、 "、および新しい行項目をディレクトリ../elsewhereのディレクトリリストに追加します。これは、「名前 'Betty.txt'は、iノード#######を介して見つけることができるデータに関連付けられています」を示しています。これが、同じドライブ上の別の場所にファイルを移動している限り、2ギガバイトのファイルを2キロバイトのファイルと同じ速さで「移動」できる理由です。]

OSは同じデータチャンクを指しているさまざまなディレクトリエントリの数を追跡する必要があるため、特定のファイルが困難であるかどうかをできますあなたが見ているディレクトリエントリが「オリジナルの」ものであるかどうかは確実にはわかりませんが、リンクされています。 1つの方法は、「ls」コマンド、具体的には「ls -l」(ダッシュの後の小文字のLです)です。

以前の例を借りるために...

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

最初の文字はダッシュなので、それはディレクトリやその他の珍しいものではなく、「通常の」通常のファイルです。しかし、それが本当に普通の場合、rwx-ish部分の後の数値は、「このデータブロックを指すディレクトリエントリが1つある」のように「1」になります。しかし、これはハードリンクのデモの一部なので、代わりに「3」と表示されます。

これは奇妙で不可解な動作につながる可能性があることに注意してください(ハードリンクに頭を抱えていなければ)。テキストエディターでFred.txtを開いて変更を加えると、Wilma.txtとBarney.txtにも同じ変更が表示されますか?多分。多分。テキストエディターが元のファイルを開いて変更を保存し、その変更をファイルに書き込んだ場合、はい、3つの名前はすべて同じ(新しく変更された)テキストを指しています。しかし、テキストエディタが新しいファイル(Fred-new-temp.txt)を作成し、変更されたバージョンをそのファイルに書き込み、Fred.txtを削除してから、Fred-new-temp.txtの名前をFred.txtに変更すると、WilmaとBarneyはまだ、変更された新しいバージョンではなく、元のバージョンを指している。ハードリンクを理解していない場合は、少し気が狂う可能性があります。 :) [さて、私は実際には個人的にnew = file/renameを行うtext editorsを知りませんが、私は知っていますまさにそれを行う他のプログラムがたくさんあるので、注意してください。]

最後の注意: 'fsck'(ファイルシステムチェック)がチェックすることの1つは、ドライブ上に何らかの形でディレクトリエントリから参照されなくなったデータブロックがあるかどうかです。時々何かがおかしくなり、iノードを指す唯一のディレクトリエントリが削除されますが、ドライブ領域自体は「利用可能」としてマークされません。したがって、fsckの仕事の1つは、割り当てられたすべてのスペースをすべてのディレクトリエントリと照合して、参照されていないファイルがないことを確認することです。見つかった場合は、新しいディレクトリエントリを作成し、「lost + found」に配置します。

4
Snarke

readlink FILE; echo $?。ハードリンクの場合は1を返し、シンボリックリンクの場合は0を返します。

Manページから:「readlinkとして呼び出された場合、シンボリックリンクのターゲットのみが出力されます。指定された引数がシンボリックリンクでない場合、readlinkは何も出力せず、エラーで終了します。」

3
user2103720