答案1
这里的区别不在于您将 放在哪里-x
,而在于您是否指定要使用的 shell(通过 shebang,或者通过使用 明确调用脚本bash -x
)。
根据man bash
,PS4
:
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 +++