如何在"$0"
和"${BASH_SOURCE[0]}"
来自GNU的描述对我没什么帮助。
BASH_SOURCE
An array variable whose members are the source filenames where the
corresponding shell function names in the FUNCNAME array variable are
defined. The shell function ${FUNCNAME[$i]} is defined in the file
${BASH_SOURCE[$i]} and called from ${BASH_SOURCE[$i+1]}
答案 0 :(得分:113)
${BASH_SOURCE[0]}
(或者更简单地说,$BASH_SOURCE
[1]
)包含所有调用方案中包含脚本的(可能相对)路径,特别是当脚本是 sourced 时,$0
不是这样。
此外,正如Charles Duffy指出的那样,调用者可以将$0
设置为任意值。
另一方面,如果没有涉及命名文件,$BASH_SOURCE
可以为空;例如: -
echo 'echo "[$BASH_SOURCE]"' | bash
以下示例说明了这一点:
脚本foo
:
#!/bin/bash
echo "[$0] vs. [${BASH_SOURCE[0]}]"
$ bash ./foo
[./foo] vs. [./foo]
$ ./foo
[./foo] vs. [./foo]
$ . ./foo
[bash] vs. [./foo]
$0
是POSIX shell规范的一部分,而BASH_SOURCE
,顾名思义,是特定于Bash的。
[1] 可选阅读:${BASH_SOURCE[0]}
与$BASH_SOURCE
:
Bash允许您使用标量表示法引用数组变量的元素0
:而不是编写${arr[0]}
,您可以编写{{ 1}};换句话说:如果您引用变量就好像它是标量,那么您将获得索引$arr
处的元素。
使用此功能掩盖了0
是一个数组的事实,这就是流行的shell-code linter shellcheck.net发出以下警告的原因(截至撰写本文时):
SC2128:扩展没有索引的数组只会给出第一个元素。
旁注:虽然此警告有用,但它可能更精确,因为您不一定会获得第一个元素:它特别是索引$arr
处的元素返回,所以如果第一个元素有一个更高的索引 - 这可能在Bash中 - 你将获得空字符串;试试0
(相比之下,'a[1]='hi'; echo "$a"'
,叛徒,确实确实返回第一个元素,无论其索引如何。)
你可以选择避开这个功能,因为它的含糊不清,但它可以预测,并且从实用角度来说,你很少需要访问索引其他而不是zsh
数组变量0
。
答案 1 :(得分:4)
为便于携带,请在定义时使用${BASH_SOURCE[0]}
,否则使用$0
。这样
${BASH_SOURCE[0]:-$0}
值得注意的是,在zsh中,即使脚本为source
d,$ 0仍包含正确的文件路径。
答案 2 :(得分:2)
这些脚本可能有助于说明。外部脚本调用中间脚本,中间脚本调用内部脚本:
$ cat outer.sh
#!/usr/bin/env bash
./middle.sh
$ cat middle.sh
#!/usr/bin/env bash
./inner.sh
$ cat inner.sh
#!/usr/bin/env bash
echo "\$0 = '$0'"
echo "\${BASH_SOURCE[0]} = '${BASH_SOURCE[0]}'"
echo "\${BASH_SOURCE[1]} = '${BASH_SOURCE[1]}'"
echo "\${BASH_SOURCE[2]} = '${BASH_SOURCE[2]}'"
$ ./outer.sh
$0 = './inner.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = ''
$BASH_SOURCE[2] = ''
但是,如果我们将脚本调用更改为source
语句:
$ cat outer.sh
#!/usr/bin/env bash
source ./middle.sh
$ cat middle.sh
#!/usr/bin/env bash
source ./inner.sh
$ cat inner.sh
#!/usr/bin/env bash
echo "\$0 = '$0'"
echo "\${BASH_SOURCE[0]} = '${BASH_SOURCE[0]}'"
echo "\${BASH_SOURCE[1]} = '${BASH_SOURCE[1]}'"
echo "\${BASH_SOURCE[2]} = '${BASH_SOURCE[2]}'"
$ ./outer.sh
$0 = './outer.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = './middle.sh'
$BASH_SOURCE[2] = './outer.sh'
答案 3 :(得分:0)
TL;DR 我建议使用 1.52.94
作为最通用的变体。
以前的答案很好,但他们没有提到直接使用 ${BASH_SOURCE:-$0}
的警告:如果您将脚本作为 ${BASH_SOURCE[0]}
的参数调用,并且您的 sh
没有别名为 {{ 1}}(就我而言,在 Ubuntu 16.04.5 LTS 上,它链接到 sh
),它可能会因 bash
变量为空/未定义而失败。举个例子:
t.sh:
dash
(成功)运行:
BASH_SOURCE
最后:
#!/usr/bin/env bash
echo "\$0: [$0]"
echo "\$BASH_SOURCE: [$BASH_SOURCE]"
echo "\$BASH_SOURCE or \$0: [${BASH_SOURCE:-$0}]"
echo "\$BASH_SOURCE[0] or \$0: [${BASH_SOURCE[0]:-$0}]"
如您所见,只有第三个变体:$ ./t.sh
$0: [./t.sh]
$BASH_SOURCE: [./t.sh]
$BASH_SOURCE or $0: [./t.sh]
$BASH_SOURCE[0] or $0: [./t.sh]
$ source ./t.sh
$0: [/bin/bash]
$BASH_SOURCE: [./t.sh]
$BASH_SOURCE or $0: [./t.sh]
$BASH_SOURCE[0] or $0: [./t.sh]
$ bash t.sh
$0: [t.sh]
$BASH_SOURCE: [t.sh]
$BASH_SOURCE or $0: [t.sh]
$BASH_SOURCE[0] or $0: [t.sh]
- 在所有调用场景下都有效并给出一致的结果。请注意,我们利用 bash's feature 来引用等于第一个数组元素的无下标数组变量。