我有一个包含单个文件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)都在运行。
我正在运行Bash 4.2.46版本的RHEL7。
答案 0 :(得分:4)
我在您的strace上放了一个strace:
$begin
S 23.1394048 -10.8890421 0.2596120
S 23.7763785 -9.4142178 0.2600115
S 24.3203694 -7.9027092 0.2596413
S 24.7669178 -6.3595161 0.2599540
S 25.1173247 -4.7917893 0.2597617
S 25.3678890 -3.2049607 0.2598870
S 25.5189950 -1.6056392 0.2599152
$end
$input
structre = ABC
Condition1 = default
Condition2 = default
Condition3 = default
Condition4 = default
Condition5 = default
Condition6 = default
$end
它挂在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
等待所有孩子,即使不是直接产卵的孩子这建议至少有两种解决方法,这两种方法似乎都可行:
strace
strace -D ls 2> >(nl)
{ strace ls; true; } 2> >(nl)
,引用手册页,“ [作为独立的孙代而不是作为示踪对象的父级来运行]示踪剂进程”。第二个强制bash通过添加另一个在其后执行的命令来使bash再次执行-D
以运行fork
。
在这两种情况下,多余的分叉都意味着进程替换不会以strace
的孩子身份结束,从而避免了该问题。