両方のディレクトリが同じ場所を指しているかどうかを確認する方法

両方のディレクトリが同じ場所を指しているかどうかを確認する方法

次のパスが同じディスクの場所を指していますか?

/home/username
/app/home/username

答え1

次に、各ディレクトリにディレクトリを変更し、pwd -Pこの-Pフラグを使用すると、pwd確認されたシンボリックリンクとともに実際の現在の作業ディレクトリが表示されます。

答え2

2つのファイルが同じであることを確認する2つの基本的な方法があります。最初はパスが同じであることを確認してください。。オタムはありませんが、オタムが多いです。間違った否定の明白なケースの1つはシンボリックリンクに関連しています。シンボリックリンクを解決してこの状況を処理できます。変更権限を持つ既存のディレクトリの場合は使用できますpwd -P

absolute_path1="$(cd -- "$path1" && pwd -P; echo .)" &&
absolute_path2="$(cd -- "$path2" && pwd -P; echo .)" &&
[ "$absolute_path1" = "$absolute_path2" ]

追加は、echo .ターゲットの1つが改行で終わるファイル名を持つまれなケースを処理します。改行がコマンドで置き換えられた最後の文字の場合は削除されるため、フラグメントはと同じfoo␤ように誤って報告されますfoo

それでも潜在的な偽の否定があります。ディレクトリの場合、ほとんどのオペレーティングシステムとファイルシステムはディレクトリハードリンクを禁止するため、ハードリンクは問題になりません。起こり得ることは、同じディレクトリが何らかの形で異なる場所で利用可能であることです。たとえば、次のようになります。

  • 同じリモートファイルシステムを2つの異なる場所にマウントします。

    mount server:/some/where /mnt1
    mount server:/some/where /mnt2
    compare /mnt1 /mnt2
    
  • バインドマウント

  • スタック可能なファイルシステム、つまりファイルシステムを別の方法で表示するシステムでは、ディレクトリビューが元のディレクトリから十分に変更されず、実際には同じディレクトリになる可能性があります。たとえば、スタック可能ファイルシステムはファイル名を変換し、ディレクトリ名は変換後も変更されません。

これらの例では、ディレクトリが実際に同じかどうかについて議論の余地があります。これは、極端な場合の「同じファイル」の概念の制限を示しています。

2番目の基本的な方法はカーネルから提供されたID(デバイスとinode)を確認してください。。これstatシステムコール各ファイルに対して2つの属性を報告します。

  • デバイス番号(st_dev)は通常、ファイルを含むファイルシステムを含むブロックデバイス(ディスクパーティション)を識別します。
  • inode番号(st_ino)は、伝統的に同じファイルシステム内のファイルを識別する一意の番号です。

通常、両方のファイルは、同じデバイス番号と inode 番号を持つ場合にのみ同じです。 Dash、ksh、bash、zsh、および少なくとも一部のBusyBoxバージョン(通常のPOSIX shではない)には、すべて以下をテストするための組み込み-ef演算test子があります。

[ "$path1" -ef "$path2" ]

これはハードリンクとシンボリックリンクを正しく処理します(シンボルリンクに従います。つまり、ファイルのシンボリックリンクをターゲットファイルと同じように処理します)。

シェル(またはtestユーティリティ)がそれをサポートしている場合は、-efすべてのファイルシステムが一意のinode番号を報告しているわけではないため、誤った肯定があることに注意してください。たとえば、ネットワークファイルシステムの場合、リモートホストが選択した inode 番号によって異なります。多くのスタック可能ファイルシステムは、デフォルトのディレクトリツリーが複数のファイルシステムにまたがっている場合、一意でないデフォルトのinodeを報告します。

他のアプローチは観察可能な同等性テスト:ディレクトリの1つを変更し、変更が他のディレクトリに反映されていることを確認します。このアプローチは原則として誤検知から安全ですが、ディレクトリを変更するには権限が必要であり、そのディレクトリを使用するシステムの他の部分を損傷する可能性があります。反映された修正を見ると、ディレクトリを非常に迅速に同期するデーモンがあることを示す可能性があるため、誤った肯定がある可能性があります。

答え3

sd(){       set '' "$1" '' "${2?sd() requires two arguments!}"
            while [ "$#" -gt 2 ]
            do    [  "${1:--L}" "${2:--L}" ${3:+"$4"} ] &&
                  [  "${1:--L}" ${3:+"-L"} "${3:-$4}" ] &&
                  [  "${2:-$3}" -ef "$4"/. ] && return  || ${1:+"return"}
                  set "$@" "$2";shift 2;set ! "$@"
            done  3>/dev/null 2>&"$((${#DBG}?2:3))"
    }

sd()まず、両方の引数がシンボリックリンクであることを確認し、そうである場合は、両方の引数が同じinodeとデバイス番号を持つディレクトリに接続されていることを確認します。もしそうなら、sd() returnそれは本当です

失敗した場合は両方を確認してください。いいえシンボリックリンクとその両方が同じデバイス番号とinode番号を持つディレクトリの場合。失敗した場合は false を返します。

だから...

ln -s dir1 ln3; ln -s dir1 ln4; ln -s dir2 ln5

sd dir1 dir2; echo $?
1
sd dir1 ln3;  echo $?
1
sd ln4 ln3;   echo $?
0
sd ln4 ln5;   echo $?
1
mount --bind dir1 dir2
sd dir1 dir2; echo $?
0

リンクを確認しない方が良いです。たとえば、リンクの宛先が特定のディレクトリと同じであるかどうかを知りたいか、リンクであるかはまったく気にしません。この場合は一度だけテストしてください[ fname1 -ef fname2 ]

ああ、これはすべてのパラメータに対する検索権限を想定していることにも言及する必要があるようです。呼び出しユーザーにテストを実行するために必要な権限がない場合、テストは失敗します。

答え4

/home/usernameとがディレクトリであると仮定すると、/app/home/usernameinode番号を確認して同じパスであることを確認することはできません。これは、ディレクトリはハードリンクできず、ソフトリンクには異なるインデックスノードがあるためです。

cd /home/usernameファイルをインポートしてtouch他のファイルに表示されることを確認できます/app/home/username。より良い方法があるかもしれないので、より良い答えを与えることができる人がいる場合は、続行してください。

関連情報