如何使用Unix命令动态地向节点脚本传递参数?

5
# index.js
console.log(process.argv) // expect this to print [.., .., '1']

# terminal
$ echo 1 | node index.js // just prints [.., ..]

有什么诀窍吗?我该如何通过类似于echolsps aux等unix命令从命令行动态地向节点脚本传递参数呢?

注意:我看到我可以使用stdin从脚本中读取unix命令的输出,但我想真正从命令行传递参数给脚本。


1
这就是说:你真正的问题是(1)如何读取管道内容,还是(2)如何读取命令行参数? - Charles Duffy
1
管道输送数据不同于传递参数,请重新措辞问题,不要使用“传递参数”这个术语,除非你想像这样调用你的脚本:node index.js 1 - zzzzBov
2
在输入流(如stdin)和argv数组之间存在显着的阻抗不匹配。 argv条目可以包含除NUL以外的任何字符,但是在stdin上轻松生成NUL分隔的流需要一些工作。 stdin流可以是完全任意长度的,而argv列表则限于适合ARG_MAX内部的内容 - 不包括导出环境变量使用的空间量。 - Charles Duffy
2
然后还有所有关于如何将前者转换为后者的问题。例如,如果您希望echo'"foo bar" baz'|...foo bar视为一个单词,将baz视为另一个单词,那么您就需要实现一个符合POSIX标准的解析器,这需要额外的工作量。 - Charles Duffy
1
顺便提一下,有一些使用xargs的技巧可以勉强做到你所要求的功能,但效果不佳——将一个过长的输入流分割成多个调用(因此echo one two three four five | xargs node yourscript可以作为两个独立命令运行node yourscript one two threenode yourscript four five)。 - Charles Duffy
显示剩余8条评论
3个回答

6
$ echo 1 | node index.js
在这个命令中,echo 打印 1 到标准输出,该输出通过管道 redirected 到接受 index.js 参数的 node 命令的标准输入。如果你想读取 echo 打印的字符串,请阅读标准输入,例如:
var text = '';

process.stdin.setEncoding('utf8');
process.stdin.on('readable', function () {
  var chunk = process.stdin.read();
  if (chunk !== null) {
    text += chunk;
  }
});
process.stdin.on('end', function () {
  console.log(text);
});

如何通过类似于echo、ls、ps aux等unix命令从命令行动态传递参数给node脚本?使用管道只能重定向一个命令的输出。您可以使用命令替换将多个命令的输出作为字符串传递,例如:
node index.js --arg1="$(ls -ld /tmp)" --arg2="$(stat -c%a /tmp)"

将命令的输出分配给shell变量,以使您的脚本更易读:
arg1="$(ls -ld /tmp)"
node index.js --arg1="$arg1"

这很有用,但并没有真正实现我想要的。我实际上想动态生成脚本的参数。 - Joseph Fraley
@JosephFraley,...你为什么想要使用管道来实现这个目的呢?更好的做法是将参数收集到一个本地shell数组中。 - Charles Duffy
@zzzzBov 有什么危险性吗?是否可以指出一些关于为什么这种使用管道是有问题的资源?@CharlesDuffy 我想使用管道因为它很方便。一个例子就是我有许多查询分别写在某个目录下的不同文件中。我想将这些文件名传递给一个Node脚本,该脚本会读取这些文件并使用它们来查询数据库。但是我也想能够手动传递文件名或手写查询字符串作为参数。ls queries | node index.js会很方便。 - Joseph Fraley
1
@JosephFraley,ls queries | node index.js 真的,真的 很有问题。请参考 ParsingLs 作为起点 -- node index.js queries/* 将优雅地处理使用 touch $'queries/hello\ncruel\nworld' 创建的文件,将其识别为一个参数并以 node 可以打开的方式传递其名称。相比之下,对于该情况,ls 的输出将不太有用。 - Charles Duffy
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - zzzzBov
显示剩余2条评论

1
一个朋友向我展示了这个:

$ node index.js `echo 1 2 3 4`

实际上正是我想要的。这将导致:
// index.js
process.argv // [.., .., '1', '2', '3', '4']

回复内容存在敏感词^**$ov的回答不同之处在于,以上代码将所有参数作为输出传递给节点进程,而:
$ node --arg1=`echo 1` --arg2=`echo 2`

每个参数都需要单独的命令。

如果文件名包含空格,则使用 ls 命令时不会按预期工作,因为空格字符被视为参数分隔符。

有关反引号在命令行调用中特别是 Git 命令方面的作用,请参见 What does the backtick - ` - do in a command line invocation specifically with regards to Git commands?


0

每次调用console.log()时,您都隐式地使用了process.stdout可写流。在内部,console.log()函数在格式化输入参数后调用process.stdout.write()。但是控制台函数更多用于调试和检查对象。当您需要将结构化数据写入stdout时,可以直接调用process.stdout.write()

假设您的程序连接到HTTP URL并将响应写入stdout。在这种情况下,Stream#pipe()非常有效,如下所示:

var http = require('http');
var url = require('url');
var target = url.parse(process.argv[2]);
var req = http.get(target, function (res) {
res.pipe(process.stdout);
});

在你能够从stdin读取之前,必须调用process.stdin.resume()指示你的脚本对来自stdin的数据感兴趣。之后,stdin就像任何其他可读流一样,当数据从另一个进程的输出或用户在终端窗口中输入按键时接收到数据时,会发出数据事件。

以下清单显示了一个命令行程序,在决定是否继续执行之前提示用户输入他们的年龄。

为了改善@Joseph's的答案,你可以在反引号()和 $(输入代码)之间同时使用两个命令:

$ node --arg1=`echo 1` --arg2=$(echo 2)

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接