Как проверить, равны ли два пути в Bash?
Каков наилучший способ проверить, равны ли два пути в Bash? Например, учитывая структуру каталогов
~/
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
Есть ли уродный способ Бэша сделать это?
Ответы
Ответ 1
Для выполнения команд 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.
Ответ 2
Вы можете использовать realpath
. Например:
realpath ~/file.txt
Result: /home/testing/file.txt
realpath ./file.txt
Result: /home/testing/file.txt
Также взгляните на аналогичный ответ здесь: команда bash/fish для печати абсолютного пути к файлу
Ответ 3
Родной путь:
pwd -P
возвращает физический каталог независимо от символических ссылок.
cd "$dir1"
real1=$(pwd -P)
cd "$dir2"
real2=$(pwd -P)
# compare real1 with real2
Другой способ - использовать cd -P
, который будет следовать символическим cd -P
, но оставит вас в физическом каталоге:
cd -P "$dir1"
real1=$(pwd)
cd -P "$dir2"
real2=$(pwd)
# compare real1 with real2
Ответ 4
Если у вас установлено coreutils 8.15 или новее, у вас есть команда realpath
которая полностью нормализует путь. Он удаляет все .
и ..
компоненты, делает путь абсолютным и разрешает все символические ссылки. Таким образом:
if [ "$(realpath "$path1")" = "$(realpath "$path2")" ]; then
echo "Same!"
fi
Ответ 5
Методы, основанные на разрешении символических ссылок, терпят неудачу при наличии других факторов. Например, привяжите монтировки. (Как mount --bind/raid0/var-cache/var/cache
Использование find -samefile
- хорошая ставка. Это будет сравнивать файловую систему и номер inode.
-samefile
- расширение GNU. Даже в Linux у busybox find, вероятно, не будет этого. Пользовательское пространство 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
Очевидно, это работает для путей, которые относятся к каталогам или любому типу файла, а не только к обычным файлам. Все они имеют номера inode.
Применение:
$ 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
для -samefile
, а также список путей. Таким образом, обе или оба могут быть символическими ссылками.