我想将当前目录更改为包含特定常规文件的 shell 脚本。我发现以下技巧在mksh
和busybox sh
中有效:
path=/path/to/regular/file
cd $path/..
但不是在 GNU Bash 中:
bash: cd: /path/to/regular/file/..: Not a directory
是这一招不兼容,还是巴什太迂腐了?
最新版本的标准不允许这样做。POSIX.1-2017cd
规范说,如果点点前面的路径名组件不是目录,cd
应将其视为错误。
从cd
§描述-步骤8.b:
b. For each dot-dot component, if there is a preceding component and
it is neither root nor dot-dot, then:
i. If the preceding component does not refer (in the context of
pathname resolution with symbolic links followed) to a
directory, then the cd utility shall display an appropriate
error message and no further steps shall be taken.
当使用-P
选项调用cd
时,将省略此步骤;但是,如果其中一个路径名组件命名的现有文件既不是目录也不是目录的符号链接,则chdir()
失败。
此外,允许该技巧还允许cd
中不一致的行为。例如,当在包含名为bar
的常规文件的目录中运行时,以及名为foo
的目录(包含另一个名为bar
的目录(时,以下两个命令在 shell 中执行不同的操作,其中cd
忽略点点前面的非目录组件,尽管CDPATH
在这两种情况下都包含空字符串(即当前工作目录(。
CDPATH= cd bar/..
CDPATH=:foo cd bar/..
下面的成绩单清楚地显示了不符合和符合实施之间的区别。
$ tree -F
.
├── bar
└── foo/
└── bar/
2 directories, 1 file
$ ash
$ CDPATH= cd bar/..
$ pwd
/home/oguz
$ CDPATH=:foo cd bar/..
/home/oguz/foo
$ bash
$ CDPATH= cd bar/..
bash: cd: bar/..: Not a directory
$ CDPATH=:foo cd bar/..
/home/oguz/foo
Bosh、GWSH、KSH93u+M 和 Yash 是其他主动维护的 shell,它们实现了与 Bash 相同的行为。