首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >脚本输出被缓冲到一条消息中,尽管有单独的echo语句?

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

Stack Overflow用户
提问于 2019-05-08 01:17:14
回答 7查看 941关注 0票数 9

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

代码语言:javascript
复制
echo 'first message'

echo 'second message'

echo 'third message'

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

代码语言:javascript
复制
var child = process.spawn('./test.sh');
child.stdout.on('data', data => {
   data = JSON.stringify(data.toString('utf8'));
   console.log(data);
});

但是单数输出是"first message\nsecond message\nthird message\n",这是一个问题。我期望有三个输出,没有一个因为某种形式的缓冲而混在一起。我不能在换行符上分开,因为单独的输出可能包含换行符。

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

编辑:我尝试过unbufferstdbuf,这两种方法都没有用,因为简单的测试可以证明这一点。下面是stdbuf尝试的一个例子,我尝试了各种不同的参数值,基本上是所有可能的选项。

代码语言:javascript
复制
 var child = process.spawn('stdbuf', ['-i0', '-o0', '-e0', './test.sh']);

要明确的是,当我从节点运行python脚本时也会出现这个问题,只有三个简单的print语句。所以它是语言不可知论的,它不是特别的bash脚本。它是关于在基于unix的系统上成功地检测任何语言中脚本的单个输出。如果这是C/C++所能做的,并且我必须从节点连接到它,我愿意去那里。欢迎任何可行的解决方案。

编辑:最初通过将脚本的输出连接到sed并使用s/$/uniqueString在每个单独输出的末尾插入标识符,然后将接收到的该标识符上的数据拆分来解决这个问题。

我给出的答案是,将工作在单行输出,但中断多行输出。我测试中的一个错误让我认为事实并非如此,但事实确实如此。接受的答案是更好的解决方案,并将工作在任何规模的输出。但是,如果您无法控制脚本并必须处理用户创建的脚本,那么我的sed解决方案是我发现的唯一有效的解决方案。它确实很管用,很好。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2019-05-16 02:25:16

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

示例:

代码语言:javascript
复制
echo -e 'one\u0016'

echo -e "two\u0016"

echo -e 'three\u0016'

结果:

代码语言:javascript
复制
"one\u0016\ntwo\u0016\nthree\u0016\n"

以及相应的Javascript:

代码语言: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);
});
票数 1
EN

Stack Overflow用户

发布于 2019-05-10 14:57:28

您可以使用作为节点API的一部分提供的readline接口。更多信息请访问line。但是,您将使用spawn,因为它将stdout传递给readline,以便它能够解析行。不知道这是不是你想要做的。下面是一些示例代码:

代码语言:javascript
复制
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);
});

输出:

代码语言:javascript
复制
"first message"
"second message"
"third message"

如果您得到类似TypeError: input.on is not a function的错误,请确保您具有通过chmod +x test.shtest.sh脚本上的执行权限。

票数 5
EN

Stack Overflow用户

发布于 2019-05-12 01:27:21

bash和python下面的C库是对stdout进行逐行缓冲的库。stdbufunbuffer会处理这个问题,但不会处理操作系统所做的缓冲工作。

例如,Linux为node.js进程和bash进程之间的管道分配4096字节作为缓冲区。

事实上,管道一端(node.js)上的进程无法看到另一端的单个写操作(echo调用)。这不是正确的设计(您可以通过单个文件而不是stdout进行通信)。

如果您坚持,您可以尝试欺骗操作系统调度程序:如果没有任何东西与管道的写入非常接近,那么它将在读取器进程(node.js)中调度--读取器进程将读取当前操作系统缓冲区中的内容。

我在Linux上测试了这个:

代码语言:javascript
复制
$ cat test.sh 
echo 'first message'
sleep 0.1
echo 'second message'
sleep 0.1
echo 'third message'
$ cat test.js 
const  child_process  = require('child_process');
var child = child_process.spawn(`./test.sh`);
child.stdout.on('data', data => {
   data = JSON.stringify(data.toString('utf8'));
   global.process.stdout.write(data); // notice global object
});
$ node test.js
"first message\n""second message\n""third message\n"
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56032290

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档