我有一个脚本依赖于一些环境变量,其中一些是路径
$(pwd)/expected-subdir
该脚本通过检查以下项来检查它是否在正确的目录中运行:$VARIABLE_PATH/expected_subdir
当然,如果$VARIABLE_PATH == $(pwd)/
(我在输入变量时自然地在变量末尾附加了一个斜杠),即使目录在技术上是正常的,字符串匹配也会失败。
有没有办法唯一地标识一个目录,给出它的路径,并查看另一条路径是否会将您路由到同一位置?给出的路径可能不合理,因此仍应进行此检查,但似乎没有必要强制路径完全匹配,因为一个斜杠甚至一个相对目录(我知道这些有时可能很糟糕)会将您路由到同一位置。
答案1
其他答案提及stat
。让我们改进一下方法:
a="$(stat --format=%d:%i -- "$(pwd)/expected-subdir/")" || printf "Error A\n" >&2
b="$(stat --format=%d:%i -- "$VARIABLE_PATH/expected-subdir/")" || printf "Error B\n" >&2
[ "$a" = "$b" ] || printf "Not the same path.\n" >&2
笔记:
- 我们正在使用
stat --format=
,因此不需要进一步解析。 %d
是设备号,%i
是 inode 号。仅后者是不够的,因为不同设备(文件系统)上的两个对象可能具有相同的 inode 号。- shell 足够智能,可以分别处理 内部和外部的引号
$( )
。 printf
-s 只是错误处理的存根。在实际脚本中,你可能需要类似[ "$a" = "$b" ] || { printf "Not the same path.\n" >&2; exit 2; }
不存在的路径将会引发
stat
错误。- 尾部斜杠很重要。如果
foo
是目录的符号链接,stat foo
将检查符号链接,同时stat foo/
将检查目录。或者研究stat -L
并使用它。 --
以...开头$(pwd)
或$VARIABLE_PATH
以...开头-
(参见准则 10这里)。
有readlink -f
(另一个答案中也提到了)和realpath
实用程序。其中一种方法可能比 更好stat
。这取决于路径的哪些方面对您来说很重要。主要区别:
- 如果
/foo/bar/
是绑定挂载,/moo/baz/
那么stat --format=%d:%i
会告诉你它们是相同的,但是readlink
或者realpath
会认为它们是不同的。 - 符号链接和 的情况就变得复杂了
..
。参见man 1 realpath
,尤其是-L
和-P
选项。
对于符号链接,如果你的脚本将目录向上更改(朝向/
,例如cd ..
),你可能会根据起始位置获得不同的结果,即使stat
或readlink -f
表示两个起点相同(比较为什么ls ..
当我位于符号链接目录中时会显示真实的父内容?)请考虑这种方法:
# early in the script
set -P
cd . # seems like no-op but updates the PWD variable to physical path
涉及绑定挂载时,如果您的脚本更改了目录,您可能会根据起始位置获得不同的结果,即使stat
两个起始点相同。考虑带有和的示例/foo/bar/
(/moo/baz/
上面已经介绍过)。显然/foo/
可能与完全不同/moo/
。但也/foo/bar/abc
可能不同于/moo/baz/abc
因为任何abc
可能是对其他东西的独立绑定挂载。因此,不仅cd ..
可能将您置于不同的位置,而且cd abc
。
嗯,abc
可能是一个文件。如果你将另一个文件绑定到/moo/baz/abc
但没有绑定到会怎么样/foo/bar/abc
?即使stat
你在同一个地方,感知到的文件也会有所不同!
由于这些问题,您可能确实更喜欢readlink
或realpath
超过stat
。
stat
,readlink
并且realpath
不是 POSIX 所要求的。对于你的情况,可移植的解决方案可能如下所示:
a="$(cd -P -- "expected-subdir" && pwd -P)" || exit 1
b="$(cd -P -- "$VARIABLE_PATH/expected-subdir" && pwd -P)" || exit 1
[ "$a" = "$b" ] || { printf "Not the same path.\n" >&2; exit 2; }
它的工作原理是cd
-ing 到任一路径并使用 检索它pwd
。这些操作明确强制以“物理”方式运行(-P
)。
set -P
也不是 POSIX。如果您希望 POSIX shell“模拟” set -P
,请将cd
和替换为pwd
:
cd() { command cd -P "$@"; }
pwd() { command pwd -P "$@"; }
POSIX 要求最后一个-P
或-L
选项才能生效,因此pwd -L
即使函数“注入” ,仍然会检索逻辑路径-P
; 也是一样cd -L
。
答案2
您可以比较它们的 inode 编号,可从以下位置获取ls -i
ls -di path/to/dir
(-d
防止ls
显示目录内容的 inode id);
或来自stat
stat path/to/dir | grep -o 'Inode:\ [0-9]*' | cut -d' ' -f2
您还可以使用它readlink -f
来获取目录的完整路径。