![bash 中的 $PS4 - 如何重现 GNU 文档中提到的“间接级别”行为?](https://linux22.com/image/210167/bash%20%E4%B8%AD%E7%9A%84%20%24PS4%20-%20%E5%A6%82%E4%BD%95%E9%87%8D%E7%8E%B0%20GNU%20%E6%96%87%E6%A1%A3%E4%B8%AD%E6%8F%90%E5%88%B0%E7%9A%84%E2%80%9C%E9%97%B4%E6%8E%A5%E7%BA%A7%E5%88%AB%E2%80%9D%E8%A1%8C%E4%B8%BA%EF%BC%9F.png)
我正在读GNU 文档,我将以下句子视为 定义的一部分PS4
:
扩展值的第一个字符根据需要被复制多次,以指示多个间接级别。默认为“+”。
我将此解释为我将+
在代码中看到每个抽象级别的符号。我想在我的 shell 中重现这种行为,所以我编写了以下代码:
#!/usr/bin/env bash
function baz() {
echo "inside baz"
}
function foo() {
echo "inside foo";
baz;
}
function bar() {
echo "inside bar";
foo;
}
set -x;
bar;
由于bar
调用foo
和foo
调用baz
,我预计最多有 3 级间接,因此我预计会看到类似以下(或类似)的输出:
+ bar
+ echo 'inside bar'
inside bar
++ foo
++ echo 'inside foo'
inside foo
+++ baz
+++ echo 'inside baz'
inside baz
然而,我所看到的并非如此。相反,我看到:
+ bar
+ echo 'inside bar'
inside bar
+ foo
+ echo 'inside foo'
inside foo
+ baz
+ echo 'inside baz'
inside baz
我是否误解了“间接级别”在这种情况下的含义,或者我只是未能正确重现所述间接级别?
答案1
正如当前接受的答案告诉您的那样,该级别与通过评估和采购增加的嵌套级别相关。它还可以通过命令替换来增加。
PS4='+ '
echo hello > world
set -x
wc -l $(ls -tc | head -1)
给出
++ ls -tc
++ head -1
+ wc -l world
1 world
如果您对函数深度感兴趣,那么您可以使用数组FUNCNAME
。例如
PS4='+ ${_plus:0:${#FUNCNAME[@]}}${FUNCNAME[0]} '
_plus='================='
bar
其工作原理如下。${#FUNCNAME[@]}
扩展到数组中的元素数量FUNCNAME
。由于当前正在调用的每个函数在数组中都有一个元素,因此这就是函数深度。然后使用该值从 中选择前 N 个字符$_plus
,将其设置为符号序列=
。中的字符数量$_plus
是一种权衡。您需要足够的内容来显示您的函数嵌套,但如果您有深层嵌套(也许您有递归函数),您也希望避免提示变得愚蠢地长。添加${FUNCNAME[0]}
显示当前功能。可以$FUNCNAME
仅引用数组的顶部元素,但如果始终将数组作为数组访问,将标量作为标量访问,则会更清楚。
根据 OP 的定义foo
,bar
这baz
给了你
$ bar
+ bar
+ =bar echo 'inside bar'
inside bar
+ =bar foo
+ ==foo echo 'inside foo'
inside foo
+ ==foo baz
+ ===baz echo 'inside baz'
inside baz
因此,+
该行开头的 告诉您 eval/source/command 替换嵌套级别,等号告诉您函数嵌套级别,然后您就有了所在的函数名称。
添加LINENO
和BASH_SOURCE
也是需要考虑添加到 PS4 提示符中的内容。
答案2
间接寻址与您观察到的函数无关,而是与 相关eval
,如以下示例所示:
#!/usr/bin/env bash
set -x
echo 1
eval "echo 2"
eval 'eval "echo 3"'
这应该发出类似的东西
+ echo 1
1
+ eval 'echo 2'
++ echo 2
2
+ eval 'eval "echo 3"'
++ eval 'echo 3'
+++ echo 3
3
而且,正如 muru 指出的那样,还提供了源文件:
$ cat code
echo help
source code
$ bash -x code
希望您的control+c已准备好并热身...