【问题标题】:different evaluation of pwd in ~/.bash_profile alias depending on type of quote~/.bash_profile 别名中 pwd 的不同评估取决于报价的类型
【发布时间】:2026-01-23 07:10:01
【问题描述】:

这发生在 OSX El Capitan 上,但也发生在我的 Ubuntu 别名中。

我为将工作目录传递给 docker 容器而创建的别名遇到了问题。

这不起作用(无论我在哪个目录中,$(pwd) 总是通过 ~/Users/username):

alias phpqa="docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa"

作品:

alias phpqa='docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa'

但是,当传入错误的路径时,我的脚本开始出现意外错误。所以我做了一个实验。我将这两个别名都添加到了我的 ~/.bash_profile 中。

alias getpath="echo $(pwd)"
alias getpath2='echo $(pwd)'

我注销然后重新登录。

更改目录:

$ cd /Users/username/correct/path/to/project

执行两个别名:

$ getpath
/Users/username

$ getpath2
/Users/username/correct/path/to/project

双引号别名总是返回用户主目录,而单引号别名返回当前目录。有人可以解释为什么会这样吗?

【问题讨论】:

  • 搜索是一门有用的知识。 *.com/questions/6697753/…
  • 如果单引号是字面的,那么当我执行用单引号包裹的“getpath2”时,为什么我没有得到“echo $(pwd)”。相反,我得到“/Users/username/correct/path/to/project”
  • 很简单,自己试试吧:echo "echo $(pwd)" aaaand echo 'echo $(pwd)' 感觉不一样?
  • 您的回答并没有解决我的问题,即为什么 $(PWD) 的评估方式取决于我的别名中的单引号和双引号
  • @IporSircer,不久前——POSIX sh 可以追溯到 90 年代。虽然,当然,它主要受 ksh 的影响,而 ksh 主要受 Bourne 的影响,所以我们当然可以将手头的决定追溯到 70 年代。

标签: macos shell alias osx-elcapitan


【解决方案1】:

别名定义像任何其他命令一样被解析。在双引号内,像$UID 这样的变量替换和像$(pwd) 这样的命令替换被扩展。在单引号内,没有任何内容被扩展:唯一的特殊字符是终止单引号文字的单引号。

alias phpqa="docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa"

假设您的用户 ID 为 1000,并且当前目录是您的主目录 /Users/username,此时您的 .bash_profile 被读取,这将定义别名 phpqa 并扩展为 docker run --rm -u 1000 -v /Users/username:/app eko3alpha/docker-phpqa

alias phpqa='docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa'

这定义了别名phpqa,扩展名为docker run --rm -u $UID -v $(pwd):/app eko3alpha/docker-phpqa。每次扩展别名时,它都会被相应的字符串替换,并且该字符串受制于通常的 shell 解析规则。所以每次使用别名时,都会使用变量UID的当前值,并执行命令pwd

这个别名的正确定义是

alias phpqa='docker run --rm -u "$UID" -v "$PWD:/app" eko3alpha/docker-phpqa'

Always use double quotes around variable and command substitutions unless you know that you need to omit them$PWD$(pwd) 是等价的(shell 在变量PWD 中跟踪当前目录)。

或者,忘记引用(替换周围的双引号除外)并使用函数。

phpqa () {
  docker run --rm -u "$UID" -v "$PWD:/app" eko3alpha/docker-phpqa "$@"
}

【讨论】:

  • 这可以解释为什么我的主目录与工作目录取决于引号的类型。谢谢你的解释!
  • 函数末尾应该有"$@" 来传递额外的参数(就像别名一样)。
  • @Eko3alpha, ...btw,Gilles 实际上在编写函数版本时修复了别名中的一堆错误——例如,它可以在名称中有空格的目录中正常工作;如果 UUID 未定义而不是运行 -u -v (从而给出更好的错误消息),将显式地将空字符串传递给 docker run;而且效率更高,因为它不会产生不必要的子shell来运行pwd。你真的应该使用这个功能。
【解决方案2】:

如果别名使用双引号,则在创建别名时评估$(pwd)

$ alias getpath="echo $(pwd)"
$ alias getpath
alias getpath='echo /Users/username'
$ cd path/to/project
$ getpath
/Users/username

如果别名使用单引号,则在使用别名时评估$(pwd)

$ alias getpath='echo $(pwd)'
$ alias getpath
alias getpath='echo $(pwd)'
$ cd path/to/project
$ getpath
/Users/username/path/to/project

【讨论】: