web-dev-qa-db-ja.com

Bashで2つのパスが等しいかどうかを確認するにはどうすればよいですか?

Bashで2つのパスが等しいかどうかを確認する最良の方法は何ですか?たとえば、ディレクトリ構造が

~/
  Desktop/
    Downloads/ (symlink to ~/Downloads)
  Downloads/
    photo.png

また、現在のディレクトリがホームディレクトリであるとすると、次のすべてが同等になります。

./                    and ~
~/Desktop             and /home/you/Desktop
./Downloads           and ~/Desktop/Downloads
./Downloads/photo.png and ~/Downloads/photo.png

これを行うネイティブのBashの方法はありますか?

20
James Ko

Bashのテストコマンドには-efこの目的のための演算子

if [[ ./ -ef ~ ]]; then ...

if [[ ~/Desktop -ef /home/you/Desktop ]]; then ...

等...

$ help test | grep -e -ef
      FILE1 -ef FILE2  True if file1 is a hard link to file2.
26
geirha

realpathを使用できます。例えば:

realpath ~/file.txt
Result: /home/testing/file.txt

realpath ./file.txt
Result: /home/testing/file.txt

ここでも同様の答えを見てください: ファイルへの絶対パスを出力するbash/fishコマンド

7
zedfoxus

ネイティブbashの方法:

pwd -Pは、シンボリックリンクに関係なく、物理ディレクトリを返します。

cd "$dir1"
real1=$(pwd -P)
cd "$dir2"
real2=$(pwd -P)
# compare real1 with real2

もう1つの方法は、cd -Pを使用することです。これは、シンボリックリンクをたどりますが、物理ディレクトリに残ります。

cd -P "$dir1"
real1=$(pwd)
cd -P "$dir2"
real2=$(pwd)
# compare real1 with real2
3
Tom Zych

Coreutils 8.15以降がインストールされている場合は、パスを完全に正規化するrealpathコマンドがあります。 .および..コンポーネント、パスを絶対パスにし、すべてのシンボリックリンクを解決します。したがって:

if [ "$(realpath "$path1")" = "$(realpath "$path2")" ]; then
   echo "Same!"
fi
3
rob mayoff

他の要因が関係している場合、シンボリックリンクの解決に基づくメソッドは失敗します。たとえば、マウントをバインドします。 (mount --bind /raid0/var-cache /var/cacheのように

find -samefileを使用することをお勧めします。ファイルシステムとiノード番号を比較します。

-samefileはGNU拡張子です。Linuxでも、busyboxの検索にはおそらくないでしょう。GNUユーザー空間とLinuxカーネルはしばしば一緒になり、しかし、どちらか一方がなくてもどちらでもかまいません。この質問にはLinuxとbashのみのタグが付けられています。)

# params: two paths.  returns true if they both refer to the same file
samepath() {
    # test if find prints anything
    [[ -s "$(find -L "$1" -samefile "$2")" ]]  # as the last command inside the {}, its exit status is the function return value
}

例えば私のシステムでは:

$ find /var/tmp/EXP/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb  -samefile /var/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb 
/var/tmp/EXP/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb


$ stat {/var/tmp/EXP,/var}/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb
  File: ‘/var/tmp/EXP/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb’
...
Device: 97ch/2428d      Inode: 2147747863  Links: 1
...

  File: ‘/var/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb’
Device: 97ch/2428d      Inode: 2147747863  Links: 1

最終パスコンポーネントのシンボリックリンクを追跡する場合は、find -Lを使用できます。

$ ln -s   /var/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb foo
$ find    /var/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb  -samefile foo
$ find -L /var/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb  -samefile foo
/var/cache/apt/archives/bash_4.3-14ubuntu1_AMD64.deb

これは明らかに、通常のファイルだけでなく、ディレクトリまたは任意のタイプのファイルを参照するパスに対して機能します。それらはすべてiノード番号を持っています。


使用法:

$ samepath /var/cache/apt/  /var/tmp/EXP/cache/apt/  && echo true
true
$ ln -sf /var/cache/apt foobar
$ samepath foobar /var/tmp/EXP/cache/apt/  && echo true
true
samepath /var/tmp/EXP/cache/apt/ foobar   && echo true
true
samepath foobar   && echo true   # doesn't return true when find has an error, since the find output is empty.
find: `': No such file or directory

したがって、find -Lは、-samefileのシンボリックリンクとパスのリストを逆参照します。したがって、どちらかまたは両方をシンボリックリンクにすることができます。

2
Peter Cordes