Hea*_*ray 3 shell pipe tr head
我正在为 nodejs使用ffi,这在很大程度上与这个问题无关,这实际上是为了更好地理解管道,但确实提供了一些上下文。
function exec(cmd) {
var buffer = new Buffer(32);
var result = '';
var fp = libc.popen('( ' + cmd + ') 2>&1', 'r');
var code;
if (!fp) throw new Error('execSync error: '+cmd);
while( !libc.feof(fp) ){
libc.fgets(buffer, 32, fp)
result += buffer.readCString();
}
code = libc.pclose(fp) >> 8;
return {
stdout: result,
code: code
};
}
Run Code Online (Sandbox Code Playgroud)
这让我想到了这段代码,当我使用这个 exec 函数运行时
tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8}
Run Code Online (Sandbox Code Playgroud)
我收到错误:
write error: Broken pipe
tr: write error
Run Code Online (Sandbox Code Playgroud)
但我确实得到了我期望的输出:8 个随机数。这让我很困惑,但后来在一些疯狂的谷歌搜索中,我发现这个堆栈答案完全适合我的情况。
不过,我还有一些问题。
为什么:
tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8}
Run Code Online (Sandbox Code Playgroud)
使用我的 exec 命令调用时抛出管道损坏错误,但从 shell 调用时则不抛出?我不明白为什么当我打电话时:
tr -dc "[:alpha:]" < /dev/urandom
Run Code Online (Sandbox Code Playgroud)
它无休止地读取,但是当我通过管道将其发送到:
head -c ${1-8}
Run Code Online (Sandbox Code Playgroud)
它可以正常工作而不会抛出损坏的管道错误。似乎这head
将需要它需要的东西,并且tr
会永远阅读。至少它应该扔断管;head
会消耗前 8 个字节,然后tr
仍然会输出输出,并且会tr
因为head
已停止运行而抛出损坏的管道。
这两种情况对我来说都有意义,但似乎它们是彼此独有的。我不明白调用之间有什么不同:
exec(tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8})
Run Code Online (Sandbox Code Playgroud)
和
tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8}
Run Code Online (Sandbox Code Playgroud)
直接从命令行,特别是为什么<
一个无尽的文件变成了某个东西,然后|
它变成了某个东西,这使得它不会无休止地运行。我已经这样做了多年,从来没有质疑过为什么会这样。
最后,可以忽略这个破损的管道错误吗?有办法解决吗?我在我的 C++ ish javascript 代码中做错了什么吗?我是否缺少某种流行的基础知识?
- - - 编辑
搞乱一些代码
exec('head -10 /dev/urandom | tr -dc "[:alpha:]" | head -c 8')
Run Code Online (Sandbox Code Playgroud)
不会抛出管道错误!
通常,tr
不应该能够写入该错误消息,因为在管道的另一端在head
.
您收到该错误消息是因为不知何故,正在运行的进程tr
已配置为忽略 SIGPIPE。我怀疑这可能是通过在popen()
那里用您的语言实现的。
您可以通过执行以下操作来重现它:
sh -c 'trap "" PIPE; tr -dc "[:alpha:]" < /dev/urandom | head -c 8'
Run Code Online (Sandbox Code Playgroud)
您可以通过执行以下操作来确认正在发生的事情:
strace -fe signal sh your-program
Run Code Online (Sandbox Code Playgroud)
(或者如果不使用 Linux,则在您的系统上等效)。然后你会看到类似的东西:
rt_sigaction(SIGPIPE, {SIG_IGN, ~[RTMIN RT_1], SA_RESTORER, 0x37cfc324f0}, NULL, 8) = 0
Run Code Online (Sandbox Code Playgroud)
或者
signal(SIGPIPE, SIG_IGN)
Run Code Online (Sandbox Code Playgroud)
在同一进程或其后代之一执行/bin/sh
解释该命令行并启动tr
和之前的一个进程中完成head
。
如果您执行 a strace -fe write
,您将看到类似以下内容:
write(1, "AJiYTlFFjjVIzkhCAhccuZddwcydwIIw"..., 4096) = -1 EPIPE (Broken pipe)
Run Code Online (Sandbox Code Playgroud)
该write
系统调用失败,并EPIPE错误而不是触发SIGPIPE。
无论如何tr
都会退出。当忽略 SIGPIPE 时,由于该错误(但也会触发错误消息)。如果不是,则在收到 SIGPIPE 时退出。你这样做要退出,因为你不希望它携带阅读做/dev/urandom
的8个字节后就一直read
通过head
。
为避免该错误消息,您可以使用以下命令恢复 SIGPIPE 的默认处理程序:
trap - PIPE
Run Code Online (Sandbox Code Playgroud)
打电话之前tr
:
popen("trap - PIPE; { tr ... | head -c 8; } 2>&1", ...)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2139 次 |
最近记录: |