web-dev-qa-db-ja.com

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

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

/home/username
/app/home/username
7

ディレクトリを順番にそれぞれに変更し、pwd -Pの出力を確認します。 -Pフラグを使用すると、pwdは、すべてのシンボリックリンクが解決された物理的な現在の作業ディレクトリを表示します。

6
Kusalananda
_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()最初に、両方の引数がシンボリックリンクであるかどうかを確認し、そうである場合は、次に、両方が同じiノードとデバイス番号のディレクトリにリンクされているかどうかを確認します。もしそうなら、sd()returns true

それができない場合は、両方がnotシンボリックリンクであるかどうか、また、両方が同じデバイス番号とiノード番号を持つディレクトリであるかどうかを確認します。それが失敗すると、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
_

リンクをチェックせずに実行することが望ましい場合があります。たとえば、リンクのターゲットがディレクトリと同じであるかどうかを知りたい場合や、リンクであるかどうかをまったく気にしない場合などです。その場合、必要なのは1つの_[ fname1 -ef fname2 ]_テストだけです。

ああ、これはすべての引数の検索権限を前提としていることにも言及する必要があると思います。呼び出し元のユーザーがテストの実行に必要な権限を持っていない場合は失敗します。

3
mikeserv

これらのフォルダを同期したり、相互にリンクしたりするために、どのメカニズム、仮想ファイルシステム、またはオーバーレイファイルシステムが存在するかを確認することはできません。単純なシンボリックリンクの場合、iノードは異なります。同じ場所であることを100%確実にするために、/home/usernameにファイルを作成できます。

touch /home/username/.testfile

次に、両方の場所でそのファイルのiノード番号を比較します。

diff <(stat -c "%i" /home/username/.testfile) <(stat -c "%i" /app/home/username/.testfile)

それらが同じである場合、それは同じファイルであるため、同じ場所を指します。

それでも、100%確信は持てません。もちろん、両方のファイルシステムで次の空きiノードの番号が同じであるため、まったくの偶然によって同じiノード番号を持つことができます...

1
chaos

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
    
  • A バインドマウント

  • スタック可能なファイルシステム。つまり、ファイルシステムを別の方法で表示する方法。ディレクトリのビューは元のビューから十分に変更されていないため、実質的に同じディレクトリであると見なされます。たとえば、ファイル名を変換するスタック可能なファイルシステムであり、ディレクトリの名前は変換時に不変です。

これらの例では、ディレクトリが本当に同じであるかどうかは議論の余地があります。これは、エッジの場合の「同じファイル」の概念の限界を示しています。

2番目の基本的な方法は、カーネルによって提供されるIDをチェックすることです:デバイスとiノードstatシステムコール は、ファイルごとに2つの属性を報告します。

  • デバイス番号(st_dev)。これは、従来、ファイルが存在するファイルシステムを含むブロックデバイス(ディスクパーティション)のIDです。
  • iノード番号(st_ino)。これは、従来、同じファイルシステム内のファイルを識別する一意の番号です。

通常、2つのファイルは、デバイス番号とiノード番号が同じである場合にのみ同一です。 Dash、ksh、bash、zsh、および少なくとも一部のBusyBoxビルド(プレーンなPOSIX shではない)には、次のことをテストするtestビルトインの-ef演算子があります。

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

これにより、ハードリンクとシンボリックリンクが正しく処理されます(シンボリックリンクがたどられます。つまり、ファイルへのシンボリックリンクはターゲットファイルと同じと見なされます)。

シェル(またはtestユーティリティ)が-efをサポートしている場合、この方法は最も簡単に実行できます。ただし、すべてのファイルシステムが一意のiノード番号を報告するわけではないため、誤検知があることに注意してください。たとえば、ネットワークファイルシステムでは、リモートホストが選択したiノード番号に翻弄されます。多くのスタック可能なファイルシステムは、基になるiノードを報告します。これは、基になるディレクトリツリーが複数のファイルシステムにまたがる場合は一意ではありません。

別のアプローチは、観察可能な同等性をテストすることです:ディレクトリの1つを変更し、変更が他のディレクトリに反映されているかどうかを確認します。このアプローチには原則としてフォールスネガティブはありませんが、ディレクトリを変更する権限が必要であり、これらのディレクトリを使用しているシステムの他の部分を混乱させる可能性があります。変更が反映されていることを確認すると、ディレクトリを非常に迅速に同期しているデーモンがあることを示している可能性があるため、誤検知が発生する可能性があります。

/home/username/app/home/usernameがディレクトリであるとすると、iノード番号をチェックしてそれらが同じパスであるかどうかを確認することはできません。これは、ディレクトリをハードリンクすることができず、ソフトリンクが異なるiノードを持っているためです。

ファイルをcd /home/usernametouchして、他の/app/home/usernameに表示されるかどうかを確認できます。おそらくもっと良い方法があります。誰かがもっと良い答えを出せるなら、先に進んでください。

0
dr_

marco の内容を拡張すると:GNU/Linuxではls -li /home/username /app/home/usernameはすでに良いヒントを提供します。両方のiノードが等しい可能性がある場合、それらは同じ場所を指しています。 mountで再確認してください。 /home/username内のファイルをtouch- ingしてトリプルチェックし、同じiノードで/app/home/usernameおよびに表示されるかどうかを確認します。そうすれば、それが同じディレクトリであるとかなり確信で​​きます。

Linux Mintマシン、3.11.0-12で行われたテスト-汎用カーネル:

# ls -ldi /var
2 drwxr-xr-x 13 root root 4096 jan 13  2014 /var

# mkdir /mnt/var
# ls -ldi /mnt/var
266483 drwxr-xr-x 2 root root 4096 jun  2 10:43 /mnt/var

# mount --bind /var /mnt/var
# ls -ldi /mnt/var
2 drwxr-xr-x 2 root root 4096 jun  2 10:43 /mnt/var

# umount /mnt/var
# mount /dev/mapper/mint--vg-var /mnt/var
# ls -ldi /mnt/var
2 drwxr-xr-x 13 root root 4096 jan 13  2014 /mnt/var

結論:私はthinkyoucanで、iノードをチェックして2つのディレクトリがマウントポイントであれば同一であることを確認します。シンボリックリンクの場合、もちろん上記は当てはまりません。しかし、それは明らかです。

# rmdir /mnt/var
# ln -s /var /mnt/
# ls -ldi /mnt/var
266483 lrwxrwxrwx 1 root root 4 jun  2 10:51 /mnt/var -> /var
0
user86969