bash 中的 $PS4 - 如何重现 GNU 文档中提到的“间接级别”行为?

Ric*_*mas 7 bash

我正在阅读GNU 文档,并且我看到以下句子作为 定义的一部分PS4

\n
\n

扩展值的第一个字符根据需要被复制多次,以指示多个间接级别。默认为 \xe2\x80\x98+ \xe2\x80\x99。

\n
\n

我将此解释为我将+在代码中看到每个抽象级别的符号。我想在我的 shell 中重现这种行为,所以我编写了以下代码:

\n
#!/usr/bin/env bash\n\nfunction baz() {\n  echo "inside baz"\n}\n\nfunction foo() {\n  echo "inside foo";\n  baz;\n}\n\nfunction bar() {\n  echo "inside bar";\n  foo;\n}\n\nset -x;\n\nbar;\n
Run Code Online (Sandbox Code Playgroud)\n

由于bar调用foofoo调用baz,我预计最多有 3 级间接,因此我预计会看到类似以下(或类似)的输出:

\n
+ bar\n+ echo \'inside bar\'\ninside bar\n++ foo\n++ echo \'inside foo\'\ninside foo\n+++ baz\n+++ echo \'inside baz\'\ninside baz\n
Run Code Online (Sandbox Code Playgroud)\n

然而,我所看到的并非如此。相反,我看到:

\n
+ bar\n+ echo \'inside bar\'\ninside bar\n+ foo\n+ echo \'inside foo\'\ninside foo\n+ baz\n+ echo \'inside baz\'\ninside baz\n
Run Code Online (Sandbox Code Playgroud)\n

我是否误解了“间接级别”在这种情况下的含义,或者我只是未能正确重现所述间接级别?

\n

ica*_*rus 8

正如当前接受的答案告诉您的那样,该级别与通过评估和采购增加的嵌套级别相关。它还可以通过命令替换来增加。

PS4='+ '
echo hello > world
set -x
wc -l $(ls -tc | head -1)
Run Code Online (Sandbox Code Playgroud)

给出

++ ls -tc
++ head -1
+ wc -l world
1 world
Run Code Online (Sandbox Code Playgroud)

如果您对函数深度感兴趣,那么您可以使用数组FUNCNAME。例如

PS4='+ ${_plus:0:${#FUNCNAME[@]}}${FUNCNAME[0]} '
_plus='================='
bar
Run Code Online (Sandbox Code Playgroud)

其工作原理如下。${#FUNCNAME[@]} 扩展到数组中的元素数量FUNCNAME。由于当前正在调用的每个函数在数组中都有一个元素,因此这就是函数深度。然后使用该值从 中选择前 N 个字符$_plus,将其设置为符号序列=。中的字符数量$_plus是一种权衡。您需要足够的内容来显示您的函数嵌套,但如果您有深层嵌套(也许您有递归函数),您也希望避免提示变得愚蠢地长。添加${FUNCNAME[0]}显示当前功能。可以$FUNCNAME仅引用数组的顶部元素,但如果始终将数组作为数组访问,将标量作为标量访问,则会更清楚。

根据 OP 的定义foobarbaz给了你

$ bar
+  bar
+ =bar echo 'inside bar'
inside bar
+ =bar foo
+ ==foo echo 'inside foo'
inside foo
+ ==foo baz
+ ===baz echo 'inside baz'
inside baz
Run Code Online (Sandbox Code Playgroud)

因此,该+行开头的 告诉您 eval/source/command 替换嵌套级别,等号告诉您函数嵌套级别,然后您就有了所在的函数名称。

添加LINENOBASH_SOURCE也是需要考虑添加到 PS4 提示符中的内容。


thr*_*rig 6

间接寻址与您观察到的函数无关,而是与 相关eval,如以下示例所示:

#!/usr/bin/env bash
set -x
echo 1
eval "echo 2"
eval 'eval "echo 3"'
Run Code Online (Sandbox Code Playgroud)

这应该发出类似的东西

+ echo 1
1
+ eval 'echo 2'
++ echo 2
2
+ eval 'eval "echo 3"'
++ eval 'echo 3'
+++ echo 3
3
Run Code Online (Sandbox Code Playgroud)

而且,正如 muru 指出的那样,还提供了源文件:

$ cat code
echo help
source code
$ bash -x code
Run Code Online (Sandbox Code Playgroud)

希望您的control+c已准备好并热身...

  • 还可以命令替换,`set -x; echo $(echo $(echo foo))` 会显示例如 `+++ echo foo` 等。哦,另一个答案已经说过了。 (3认同)