Строка запроса PS4 дублирует себя при использовании набора -x

Моя операционная система: Ubuntu 18.04.5 LTS

Я использую трассировку для поиска и устранения неисправностей в сценарии. Я заметил различное поведение трассировки в зависимости от того, как я ее настроил. Хотелось бы понять, почему он так себя ведет.

Обычно я активирую трассировку, используя набор -x в своем скрипте, где мне нужно, чтобы трассировка проходила. Однако Prompt String PS4 ("+ " по умолчанию), кажется, "дублирует" себя.

enter image description here

Если я активирую трассировку в строке shebang #!, то PS4 печатается только один раз.

enter image description here

Аналогично, если я вызываю bash непосредственно для выполнения моего скрипта и указываю -x в командной строке, PS4 также печатается только один раз.

enter image description here

Почему в первом примере set -x ведет себя по-другому ? Наверное, в оболочке есть что-то фундаментальное, чего я не понимаю...

1
задан 7 October 2020 в 04:29

1 ответ

Различие здесь не в том, куда вы помещаете -x, а в том, указываете ли вы оболочку для использования (через шебанг или явно вызывая скрипт с помощью bash -x).

Согласно man bash, PS4:

 PS4 Значение этого параметра расширено как для PS1, так и для
значение печатается перед отображением каждой команды bash во время
след исполнения. Первый персонаж PS4 реплицирован несколько раз.
несколько раз, по мере необходимости, чтобы указать несколько уровней отдельных
реакция. По умолчанию это ``+ ''.

однако не сообщается, что означает «уровни косвенности» в этом контексте.

При попытке выполнить текстовый файл без указания используемого интерпретатора системный вызов execve завершается с ошибкой ENOEXEC (ошибка формата Exec). Что произойдет дальше, зависит от оболочки, из которой вы пытаетесь его выполнить, как описано здесь:

В частности, если вызывается оболочка bash, тогда кажется, что сценарий выполняется непосредственно вызывающей оболочкой: это похоже на «косвенность», упомянутую в руководстве:

$ 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 здесь принимает место вашей интерактивной оболочки, а не bash -x, который вы использовали в своем последнем примере.

Как только мы добавим шебанг, напр.:

$ cat hw_shebang
#!/bin/bash

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

then (независимо от того, вызывается ли -x с помощью set или иным образом), то execve завершается успешно, и скрипт выполняется в собственной оболочке, без «косвенности»:

$ 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 он бы execved /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 +++
1
ответ дан 7 October 2020 в 00:45

Другие вопросы по тегам:

Похожие вопросы: