尽管有单独的echo语句,脚本输出仍被缓冲到一条消息中?

tem*_*ame 9 unix linux shell child-process node.js

我有一个包含三个echo语句的shell脚本:

echo 'first message'

echo 'second message'

echo 'third message'
Run Code Online (Sandbox Code Playgroud)

然后,我在节点中运行此脚本,并通过以下代码收集输出:

var child = process.spawn('./test.sh');
child.stdout.on('data', data => {
   data = JSON.stringify(data.toString('utf8'));
   console.log(data);
});
Run Code Online (Sandbox Code Playgroud)

但是单个输出是"first message\nsecond message\nthird message\n",这是一个问题。我期望有三项输出,而不是由于某种形式的缓冲而浪费的。而且我不能只在换行符上分开,因为单个输出可能包含换行符。

有什么方法可以区分单个echo语句的消息吗?(或其他输出命令,即printf,或导致数据写入stdout或stderror的任何命令)

编辑:我已经尝试过unbufferstdbuf,但都没有用,因为简单的测试就可以证明这一点。这是stdbuf尝试的示例,我尝试了各种不同的参数值,基本上是所有可能的选项。

 var child = process.spawn('stdbuf', ['-i0', '-o0', '-e0', './test.sh']);
Run Code Online (Sandbox Code Playgroud)

明确地说,当我也仅用三个简单的print语句从节点运行python脚本时,就会发生此问题。因此,它与语言无关,尤其与bash脚本无关。这是关于在基于unix的系统上成功检测任何语言的脚本的单个输出的信息。如果这是C / C ++可以做的事情,而我必须从node入手,那么我愿意去那里。任何可行的解决方案都是值得欢迎的。


编辑:我最初为自己解决了这个问题,方法是将脚本的输出管道传递到seds/$/uniqueString用于在每个单独输出的末尾插入一个标识符,然后将接收到的数据拆分到该标识符上。

我给予的赏金答案将适用于单行输出,但不适用于多行输出。测试中的错误使我认为不是这种情况,而是事实。公认的答案是更好的解决方案,并且适用于任何大小的输出。但是,如果您无法控制脚本而必须处理用户创建的脚本,那么我sed发现的唯一解决方案就是我的解决方案。它确实可以正常工作。

man*_*shg 5

您可以使用readline作为节点API一部分提供的接口。有关更多信息,请参见https://nodejs.org/api/readline.html#readline_event_line。您将按spawn原样使用,但可以将其传递给stdoutreadline以便它可以解析行。不确定这是否是您要执行的操作。这是一些示例代码:

var process = require('child_process');
const readline = require('readline');

var child = process.spawn('./test.sh');

// Use readline interface
const readlinebyline = readline.createInterface({ input: child.stdout });

// Called when a line is received
readlinebyline.on('line', (line) => {
    line = JSON.stringify(line.toString('utf8'));
    console.log(line);
});
Run Code Online (Sandbox Code Playgroud)

输出:

"first message"
"second message"
"third message"
Run Code Online (Sandbox Code Playgroud)

如果出现类似错误TypeError: input.on is not a function,请确保您通过拥有对test.sh脚本的执行特权chmod +x test.sh


its*_*ben 1

我在之前的项目中遇到了同样的问题。我在 echo 语句上使用了解释开关,然后将字符串拆分为不可打印的字符。

例子:

echo -e 'one\u0016'

echo -e "two\u0016"

echo -e 'three\u0016'
Run Code Online (Sandbox Code Playgroud)

结果:

"one\u0016\ntwo\u0016\nthree\u0016\n"
Run Code Online (Sandbox Code Playgroud)

以及相应的Javascript:

var child = process.spawn('./test.sh');
child.stdout.on('data', data => {
   var value = data.toString('utf8');
   var values = value.split("\u0016\n").filter(item => item);
   console.log(values);
});
Run Code Online (Sandbox Code Playgroud)