更改到调用脚本的目录的最安全(或最优雅或最短)方法是什么?

sys*_*yss 0 bash cd-command posix pwd

我想知道更改到调用脚本的目录的安全或 Unix 兼容方式是什么。

这两种方法甚至可以在包含空格和特殊字符的目录中工作,而无需使用引号。但是在某些情况下这可能不起作用。或者有吗?

#!/bin/bash

cd $(dirname $0)
pwd
cd ${0%/*}
pwd

~/test 1"\ ü`\($$ ./cd.sh
/home/syss/test 1"\ ü`\($
/home/syss/test 1"\ ü`\($
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 5

请注意,这$0可能是相对路径,因此调用cd两次可能不起作用。除此之外$0大多数情况下提取目录部分是有效的。大多数是不一样的一切。它可能失败的一些情况包括:

  • 该脚本不是通过运行其路径而是通过调用它的外壳程序来调用的,例如bash myscript(它进行PATH查找)。
  • 脚本在执行过程中被移动。

只要您记录必须在没有恶作剧的情况下调用您的脚本,就可以使用 的目录部分$0

你需要小心一点;可能$0根本不包含斜杠,如果它是通过空PATH条目找到的,或者在某些 shell 中PATH找到.. 这个案例值得支持,这意味着您需要对${0%/*}.

这种dirname方法也不是完全直接的。命令替换在最后吃掉换行符。使用这两种方法,您需要注意字符串可以以开头-并被解释为选项;pass--终止命令的选项列表。

case "$0" in
  */*) cd -- "${0%/*}";;
  *) cd -- "$0";;
esac
Run Code Online (Sandbox Code Playgroud)

或者

cd -- "$(dirname -- "$0"; echo /)"
Run Code Online (Sandbox Code Playgroud)

关于双引号,你问错了问题。"$0"是参数的值0$0,未加引号,是0IFS每个元素的字符处拆分的参数值,然后将其解释为 glob 模式并替换为匹配文件(如果有的话,后者仅在未关闭 globbing 的情况下)。你不是说参数的值0IFS每个元素的字符处拆分,然后解释为 glob 模式并替换为匹配的文件(如果有的话,后者只有在 globbing 没有关闭的情况下),对吗?你的意思是参数的值0。所以写下你的意思:"$0"

您的测试没有卡住的唯一原因是您没有尝试使用有问题的名称,而是使用特定的外壳进行测试,该外壳恰好可以修复您在此特定场景中的错误。使用类似 的目录名称foo bar,您最终会向命令传递两个参数foo和;bash 的命令将此解释为“更改到通过连接、空格和”获得的目录,因此它恰好重建了正确的名称。不同的 shell 可能会将其解释为“抱怨虚假参数”、“更改到目录”或“更改到通过在当前工作目录中替换而获得的目录”。例如,使用 bash,如果名称包含两个连续的空格,您的脚本就会失败。barcdcdfoobarfoofoobar