2009-07-25 09:41:26 +0000 2009-07-25 09:41:26 +0000
104
104
Advertisement

lsで実際のハードリンクを見るにはどうすればいいのでしょうか?

Advertisement

私は

ln /a/A /b/B

を実行して、ファイルAがaで指し示すフォルダlsで確認したいと思います。

Advertisement
Advertisement

回答 (9)

182
182
182
2009-07-25 10:01:32 +0000
ls -i

でファイルの inode 番号を見つけることができ、

ls -l

は参照数(特定の inode へのハードリンク数)を表示します。

find . -inum NUM

は、現在のディレクトリ(.)のinode NUMのファイル名を表示します。

66
66
66
2009-07-25 09:51:57 +0000

あなたの質問に対する明確な答えはありません。シンボリックリンクとは異なり、ハードリンクは「元のファイル」と区別がつきません。

ディレクトリエントリは、ファイル名とinodeへのポインタで構成されています。inodeにはファイルのメタデータと実際のファイルの内容が含まれています。ハードリンクを作成すると、別のファイル名と同じinodeへの参照が作成されます。これらの参照は(少なくとも典型的なファイルシステムでは)一方向です – inodeは参照数を保持するだけです。どちらが「元の」ファイル名なのかを調べる方法は本質的にはありません。

ところで、ファイルを「削除」するためのシステムコールが unlink と呼ばれるのはこのためです。これはハードリンクを削除しているだけです。

与えられたinodeへの他の参照を見つける唯一の方法は、どのファイルが問題のinodeを参照しているかを確認しながらファイルシステムを徹底的に検索することです。このチェックを行うには、シェルから'test A -ef B'を使うことができます。

24
Advertisement
24
24
2009-07-25 10:01:38 +0000
Advertisement
ls -l

最初の列はパーミッションを表します。2番目の列は、サブ項目の数(ディレクトリの場合)や、そのファイルと同じデータ(元のファイルを含むハードリンク)へのパスの数を表します。例:

-rw-r--r--@ 2 [username] [group] [timestamp] HardLink
-rw-r--r--@ 2 [username] [group] [timestamp] Original
               ^ Number of hard links to the data
14
14
14
2013-08-15 08:52:16 +0000

以下のようなシンプルなものはどうでしょうか?

find <TARGETDIR> -type f -samefile <THEFILENAME>

論理を拡張して、複数のハードリンクが<THEFILENAME> に分散している<TARGETDIR> の中の全てのファイルを知りたい場合。

find <SOURCEDIR> -type f -links +1 \
  -printf "\n\n %n HardLinks of file : %H/%f \n" \
  -exec find <TARGETDIR> -type f -samefile {} \;
6
Advertisement
6
6
2015-04-21 19:32:47 +0000
Advertisement

ファイルシステム内のすべてのハードリンクを見つけるスクリプトを使った回答はたくさんあります。ほとんどのスクリプトは、ファイルシステム全体をスキャンするために find を実行して、マルチプルリンクされたファイルごとに -samefile を探すような馬鹿げたことをしています。必要なのは inode 番号でソートして重複を表示することだけです。

ハードリンクされたファイルのすべてのセットを見つけてグループ化するためにファイルシステムを1回通過するだけで

find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
    sort -n | uniq -w 42 --all-repeated=separate

ハードリンクされたファイルの複数セットを見つけるために、他の回答よりもはるかに高速です。
find /foo -samefile /bar は、1 つのファイルだけを見つけるのに優れています。

  • -xdev : 1つのファイルシステムに制限。
  • ! -type d で uniq に FS-id も出力するので厳密には必要ありません。
  • . : リンクカウントを厳密に ..
  • -links +1 FS-id、inode番号、パスを表示する。
  • > 1 数値ソートと一意性化を最初の42列で行い、空白行でグループを区切る

-printf ... を使用すると、ソートの入力は uniq の最終出力と同じ大きさしかないので、膨大な量の文字列ソートは行わないことになります。ハードリンクのセットの一つしか含まれていないサブディレクトリで実行しない限り。いずれにしても、この方法は他のどのソリューションよりも、ファイルシステムの再トラバースにかかるCPU時間を大幅に削減できます。

サンプル出力。

...
            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はフィールド選択のサポートが非常に限られているので、私は検索出力にパッドを入れて固定幅を使用しています。20charsは最大可能なinodeまたはデバイス番号(2^64-1 = 18446744073709551615)のために十分な幅です。XFS は、ディスク上のどこに割り当てられたかに基づいて inode 番号を選択しますが、0 から連続しているわけではありませんので、大規模な XFS ファイルシステムでは、何十億ものファイルがなくても、32 ビット以上の inode 番号を持つことができます。他のファイルシステムでは、巨大なファイルでなくても、20桁のinode番号を持つかもしれません。

TODO: 重複ファイルのグループをパスでソートする。マウントポイントでソートしてから inode 番号でソートすると、ハードリンクがたくさんあるいくつかの異なるサブディレクトリを持っている場合に、物事が混ざってしまいます。(つまり、重複グループのグループは一緒になっているが、出力ではそれらが混ざってしまう)。

最後の sort -n | uniq ... は、行のグループを一つのレコードとしてではなく、行を別々にソートします。改行のペアをNULバイトに変換する何かで前処理を行い、GNU ! -type d -links +1を使用するとうまくいくかもしれません。awk は単一の文字に対してのみ動作し、2->1 や 1->2 パターンでは動作しない。cutならそれができるだろう(あるいは、Perlやawkの中でパースしてソートするだけ)。uniqも使えるかもしれません。

3
3
3
2012-06-13 07:40:43 +0000

情報を見つけるためのよりわかりやすい方法であなたのスクリプトを書き直しました。

#!/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は強力です。

  • headtail の呼び出しは、awk コマンドや exit 変数の選択などで、NR で直接処理することができます。これにより、プロセスの呼び出しが省かれますが、これはハードワークなスクリプトではほとんどの場合、パフォーマンスを著しく低下させることになります。

  • あなたのegrepはただのgrepであることができます。

2
Advertisement
2
2
2011-11-16 22:46:38 +0000
Advertisement

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 "";
1
1
1
2015-01-20 18:00:05 +0000

GUIソリューションは、あなたの質問に本当に近いものになります。

以前のコメンテーターが指摘したように、ファイルの「名前」は同じデータへの単なるエイリアスだからです。しかし、実際には、Linux上で同じデータを指す(ハードリンクとしての)ファイル名のパスリストを表示するGUIツールがあり、それはFSLintと呼ばれています。欲しいオプションは “Name clashes "の下の "Name clashes” -> Search (XX)の “checkbox $PATH "の選択を解除して、"for… "の後にあるドロップダウンボックスから "Aliases "を選択します。

FSLintのドキュメントは非常に貧弱ですが、「Search path」の下の限定されたディレクトリツリーを「Recurse?

1
Advertisement
1
1
2017-12-06 17:34:25 +0000
Advertisement

ls は「エイリアス」を使ってハードリンクをハイライトするように設定できますが、前に述べたようにハードリンクの「ソース」を表示する方法がないので、これを助けるために .hardlink を追加しました。

.bashrc alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first' のどこかに以下を追加してください。

Advertisement

関連する質問

6
10
10
5
1
Advertisement