我正在玩节点流和子进程。所以我想用管道模拟下一个 shell 命令:
ps au | grep ssh
所以我写了下一段代码:
var spawn = require('child_process').spawn;
var ps = spawn('ps', ['au']);
var grep = spawn('grep', ['ssh']);
ps.stdout.pipe(grep.stdin);
grep.stdout.on('data', function(data) { console.log(data) });
然后我运行它,但没有任何反应。我做错了什么?
附言 - 我知道:
require('child_process')
.exec('ps au | grep ssh', function(err, stdout, stderr) {
...
}).
我只是在玩 Node.js,我想了解这个例子有什么问题。
更新 1:
看起来 grep bash
程序按预期工作,但使用 grep ssh
没有结果。虽然ps au | grep ssh
给了我这个结果:
vagrant 11681 0.0 0.1 10464 916 pts/0 S+ 07:54 0:00 grep --color=auto ssh.
当您调用ps
时,它将列出与传递的选项匹配的所有当前正在运行的进程。这可能会寻找这样的ps au
:
tniese 3251 0,0 0,0 2479028 3004 s000 S+ 4:06am 0:00.03 -bash
root 4453 0,0 0,0 2452408 876 s004 R+ 4:06pm 0:00.00 ps au
当您在 shell 中调用 ps au | grep ssh
时grep
将过滤该结果以仅显示包含 ssh
的行。
如果 shell 在创建其列表之前启动grep
ps
则筛选之前的输出将是:
tniese 3251 0,0 0,0 2479028 3004 s000 S+ 4:06am 0:00.03 -bash
root 4453 0,0 0,0 2452408 876 s004 R+ 4:06pm 0:00.00 ps au
tniese 4478 0,0 0,0 2441988 596 s000 R+ 4:06pm 0:00.00 grep ssh
grep
进程将匹配其自己的条目,因为它包含传递的参数,因此过滤结果将是:
tniese 4478 0,0 0,0 2441988 596 s000 R+ 4:06pm 0:00.00 grep ssh
让我们看看你的代码发生了什么:
var spawn = require('child_process').spawn;
var ps = spawn('ps', ['au']);
var grep = spawn('grep', ['ssh']);
ps.stdout.pipe(grep.stdin);
使用 spawn,您可以告诉操作系统ps
启动进程,ps
不需要等到输出可以通过管道传输到任何地方才能运行,但可以在此之前启动,它可能只会在尝试写入其输出流时被迫等待。然后你的生成grep
,但在启动grep
时,ps
可能已经在内部创建了进程列表,并且由于它不包含grep
进程。然后将ps
的输出传递给 grep。但是由于缺少此输出grep ssh
因此它不会显示该行。
grep
是否出现在您的列表中是高度依赖操作系统的。通常,您应该假设它是否被列出是随机的。或者您需要等到ps
退出并在此之后启动grep
。
您需要始终记住,当前操作系统具有抢占式多任务处理,并且调度程序可能会在spawn('ps', ['au']);
后立即暂停节点,并在创建/请求列表后立即ps
继续该过程。
我希望这个解释比我的评论更清楚一些。
我在 ps 之前生成了 grep,现在它运行良好。我认为这一定是一个时间问题。试试这个。
var spawn = require('child_process').spawn;
var grep = spawn('grep', ['ssh']);
var ps = spawn('ps', ['au']);
ps.stdout.pipe(grep.stdin);
grep.stdout.on('data', function(data) {
console.log(data.toString("utf8"));
});