使用 set -x 时提示字符串 PS4 重复

使用 set -x 时提示字符串 PS4 重复

我的操作系统:Ubuntu 18.04.5 LTS

我使用跟踪来排除脚本故障。我注意到跟踪中的行为根据我的设置方式而有所不同。我想了解它为什么会这样表现。

我通常set -x在需要进行跟踪的脚本中使用 来激活跟踪。但是,提示字符串 PS4(默认为“+”)似乎“重复”了自身。

在此处输入图片描述

如果我在 shebang #! 行中激活跟踪,PS4 只会打印一次。

在此处输入图片描述

类似地,如果我bash直接调用运行我的脚本,并-x在命令行中指定,PS4 也只会打印一次。

在此处输入图片描述

为什么set -x第一个例子中的行为有所不同?我猜想 shell 中有一些基本的东西我在这里没有讲清楚...

答案1

这里的区别不在于您将 放在哪里-x,而在于您是否指定要使用的 shell(通过 shebang,或者通过使用 明确调用脚本bash -x)。

根据man bashPS4

   PS4    The value of this parameter is expanded  as  with  PS1  and  the
          value  is  printed  before  each command bash displays during an
          execution trace.  The first character of PS4 is replicated  mul‐
          tiple  times, as necessary, to indicate multiple levels of indi‐
          rection.  The default is ``+ ''.

然而,它并没有透露具体细节“间接层级”在此上下文中意味着。

当您尝试执行文本文件而不指定要使用的解释器时,系统调用将execve失败并显示ENOEXEC (Exec format error)。接下来发生的情况取决于您尝试执行它的 shell,如下所述:

具体来说,如果调用 shell 是bash,那么脚本似乎由调用 shell 直接执行:这似乎是手册中提到的“间接”:

$ strace -e trace=%process -f bash -c 'echo "Starting $0"; ./hw_no_shebang; echo "Finished."'
execve("/bin/bash", ["bash", "-c", "echo \"Starting $0\"; ./hw_no_sheb"...], 0x7ffd3dadbee8 /* 25 vars */) = 0
arch_prctl(ARCH_SET_FS, 0x7f95fe939740) = 0
Starting bash
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f95fe939a10) = 26515
strace: Process 26515 attached
[pid 26514] wait4(-1,  <unfinished ...>
[pid 26515] execve("./hw_no_shebang", ["./hw_no_shebang"], 0x555e5058a4f0 /* 25 vars */) = -1 ENOEXEC (Exec format error)
++ echo Hello
Hello
++ echo World
World
++ set +x
[pid 26515] exit_group(0)               = ?
[pid 26515] +++ exited with 0 +++
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 26515
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26515, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, 0x7fffba5272d0, WNOHANG, NULL) = -1 ECHILD (No child processes)
Finished.
exit_group(0)                           = ?
+++ exited with 0 +++

请注意,bash -c此处的 strace 调用中的 取代了您的交互式 shell,而不是bash -x您在上一个示例中使用的 。

一旦我们添加了shebang,例如:

$ cat hw_shebang
#!/bin/bash

set -x
echo "Hello"
echo "World"
set +x

然后(无论是-x使用set还是以其他方式调用),然后execve成功并且脚本在其自己的 shell 中执行,没有“间接”:

$ strace -e trace=%process -f bash -c 'echo "Starting $0"; ./hw_shebang; echo "Finished."'
execve("/bin/bash", ["bash", "-c", "echo \"Starting $0\"; ./hw_shebang"...], 0x7ffccc0af338 /* 25 vars */) = 0
arch_prctl(ARCH_SET_FS, 0x7f81b9ed2740) = 0
Starting bash
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f81b9ed2a10) = 26553
strace: Process 26553 attached
[pid 26552] wait4(-1,  <unfinished ...>
[pid 26553] execve("./hw_shebang", ["./hw_shebang"], 0x55879d9924f0 /* 25 vars */) = 0
[pid 26553] arch_prctl(ARCH_SET_FS, 0x7fa55de83740) = 0
+ echo Hello
Hello
+ echo World
World
+ set +x
[pid 26553] exit_group(0)               = ?
[pid 26553] +++ exited with 0 +++
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 26553
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26553, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, 0x7ffda2983b10, WNOHANG, NULL) = -1 ECHILD (No child processes)
Finished.
exit_group(0)                           = ?
+++ exited with 0 +++

例如,如果你从中调用 no-shebang 脚本dash,行为将会有所不同:在初始失败后execve,它将执行该脚本:execve/bin/sh

$ strace -e trace=%process -f dash -c 'echo "Starting $0"; ./hw_no_shebang; echo "Finished."'
execve("/bin/dash", ["dash", "-c", "echo \"Starting $0\"; ./hw_no_sheb"...], 0x7ffc283d8638 /* 25 vars */) = 0
arch_prctl(ARCH_SET_FS, 0x7fd2cc787540) = 0
Starting dash
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fd2cc787810) = 26590
strace: Process 26590 attached
[pid 26589] wait4(-1,  <unfinished ...>
[pid 26590] execve("./hw_no_shebang", ["./hw_no_shebang"], 0x557143e3c8d8 /* 25 vars */) = -1 ENOEXEC (Exec format error)
[pid 26590] execve("/bin/sh", ["/bin/sh", "./hw_no_shebang"], 0x557143e3c8d8 /* 25 vars */) = 0
[pid 26590] arch_prctl(ARCH_SET_FS, 0x7f3b9aa14540) = 0
+ echo Hello
Hello
+ echo World
World
[pid 26590] exit_group(0)               = ?
[pid 26590] +++ exited with 0 +++
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 26590
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26590, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
Finished.
exit_group(0)                           = ?
+++ exited with 0 +++

相关内容