Почему эта полоса на конвейере не заканчивается - PullRequest
0 голосов
/ 07 сентября 2018

У меня есть каталог с одним файлом, one.txt. Если я запускаю ls | cat, он работает нормально. Однако, если я попытаюсь связать обе стороны этого конвейера, я увижу вывод команды и strace, но процесс не завершится.

strace ls 2> >(stdbuf -o 0 sed 's/^/command1:/') | strace cat 2> >(stdbuf -o 0 sed 's/^/command2:/')

Вывод, который я получаю:

command2:execve("/usr/bin/cat", ["cat"], [/* 50 vars */]) = 0
command2:brk(0)                                  = 0x1938000
command2:mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f87e5a93000
command2:access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
<snip>
command2:open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
command2:fstat(3, {st_mode=S_IFREG|0644, st_size=106070960, ...}) = 0
command2:mmap(NULL, 106070960, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f87def8a000
command2:close(3)                                = 0
command2:fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
command2:fstat(0, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
command2:fadvise64(0, 0, 0, POSIX_FADV_SEQUENTIAL) = -1 ESPIPE (Illegal seek)
command2:read(0, "command1:execve(\"/usr/bin/ls\", ["..., 65536) = 4985
command1:execve("/usr/bin/ls", ["ls"], [/* 50 vars */]) = 0
command1:brk(0)                                  = 0x1190000
command1:mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fae869c3000
command1:access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
<snip>
command1:close(3)                                = 0
command1:fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
command2:write(1, "command1:close(3)               "..., 115) = 115
command2:read(0, "command1:mmap(NULL, 4096, PROT_R"..., 65536) = 160
command1:mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fae869c2000
one.txt
command1:write(1, "one.txt\n", 8)                = 8
command2:write(1, "command1:mmap(NULL, 4096, PROT_R"..., 160) = 160
command2:read(0, "command1:close(1)               "..., 65536) = 159
command1:close(1)                                = 0
command1:munmap(0x7fae869c2000, 4096)            = 0
command1:close(2)                                = 0
command2:write(1, "command1:close(1)               "..., 159) = 159
command2:read(0, "command1:exit_group(0)          "..., 65536) = 53
command1:exit_group(0)                           = ?
command2:write(1, "command1:exit_group(0)          "..., 53) = 53
command2:read(0, "command1:+++ exited with 0 +++\n", 65536) = 31
command1:+++ exited with 0 +++
command2:write(1, "command1:+++ exited with 0 +++\n", 31) = 31

и с тех пор зависает. ps показывает, что обе команды в конвейере (здесь находятся ls и cat).

Я использую RHEL7 под управлением Bash версии 4.2.46.

1 Ответ

0 голосов
/ 07 сентября 2018

Я наложил на твой ремень:

strace bash -c 'strace true 2> >(cat > /dev/null)'

Он висит на wait4, указывая, что он застрял в ожидании детей. ps f подтверждает это:

24740 pts/19   Ss     0:00 /bin/bash
24752 pts/19   S+     0:00  \_ strace true
24753 pts/19   S+     0:00      \_ /bin/bash
24755 pts/19   S+     0:00          \_ cat

Исходя из этого, моя рабочая теория заключается в том, что этот эффект является тупиком, потому что:

  1. strace ждет всех детей, даже тех, которых он не породил напрямую
  2. Bash порождает замену процесса как дочерний процесс. Поскольку подстановка процесса присоединена к stderr, он по существу ожидает выхода из родительского процесса.

Это предполагает, по крайней мере, два обходных пути, оба из которых работают:

strace -D ls 2> >(nl)

{ strace ls; true; } 2> >(nl)

-D, чтобы процитировать man-страницу, «[запускает] процесс трассировки как отдельный внук, а не как родитель трассировки». Второй заставляет bash выполнить еще один fork для запуска strace, добавив еще одну команду после.

В обоих случаях дополнительные вилки означают, что подстановка процесса не заканчивается как потомство strace, что позволяет избежать проблемы.

...