为什么 #!/usr/bin/env 将“$@”显示为 1?

为什么 #!/usr/bin/env 将“$@”显示为 1?

如果我有 test.sh:

#!/usr/bin/env bash
echo "$@"

bash test.sh结果是1

知道为什么结果是 1 吗?另外,为什么要发送到 env 而不是直接发送到 bash?

更新:抱歉,我遗漏了一些代码,现在有了这些代码,就有意义了。

#!/usr/bin/env bash
main() {
  echo ${1:-1}
}
main "$@"

答案1

我无法在 Ubuntu 18.04.1 上重现此问题。

您应该echo "$@"在脚本之外进行测试。它将显示1您是否之前输入过set 1,或者任何先前的位置参数命令的结果set(包括在启动脚本中)。

请注意,作为( ) 文件bash test.sh运行,任何行都将被忽略。要执行此操作,您需要:test.shsource.#!!#

bash -c test.sh

至于为什么env指定,我不知道,除非它是作为占位符添加的:如果它包含一个或多个环境规范,它将产生效果。例如,以下内容将指定bash使用自定义启动文件运行:

!#/usr/bin/env BASH_ENV=BashStart bash
...

Attie 的回答表明的另一个原因是,在 OSX 中bash默认情况下不是在 中/bin/,而是env在 中/usr/bin/,就像在 Linux 中一样,因此!#/usr/bin/env bash允许在bash将在 Linux 或 OSX 中运行的脚本中将其指定为 shell。

答案2

这 ”缺失代码”十分有意义。

#!/usr/bin/env bash

main() {
  echo ${1:-1}
}

main "$@"

在这里,我们调用该main函数并提供"${@}"(即:我们所有的参数,保持分离)。

${@}扩展为无(即:脚本被调用时没有参数)时,main()使用参数,因此函数${1:-1}内部main()将产生特殊效果,如“参数替换“语义。

具体来说,如果声明了且非 NULL,或者未声明或为 NULL,${parameter:-default}则将扩展为 的值。请注意 的行为与 略有不同。${parameter}default${parameter:-default}${parameter-default}

${parameter-default}和几乎等同。仅当参数已声明但为空时,${parameter:-default}extra才有区别。:

因此${1:-1}将扩展到给定的第一个参数,或者默认为1

$ ./script.sh
1
$ ./script.sh test
test

/usr/bin/env在shebang中的使用使我们能够“用作bash解释器“而不提供完整路径bash...env将搜索当前环境${PATH}并使用第一个匹配的候选项。shebang 需要解释器的绝对路径,我们可以通过使用来绕过这个限制env

这在 Python 脚本中很常见,因为解释器可以位于许多位置 - 尽管通常/usr/bin/python它支持以下内容虚拟环境也。

看 ”为什么人们在 Python 脚本的第一行写 #!/usr/bin/env python shebang?” 以进行更多讨论。

相关内容