从管道中获取参数,但也有 运行 提示?

Get argument from pipe but also run prompts?

我正在编写一个旨在从 Bash 终端执行的 Node 脚本。它需要几个文件名,然后通过提示向用户询问如何处理它们。我正在使用 yargs 来解析命令行参数,并使用 prompt-sync 来询问用户问题,而且一切似乎都正常...

除非我像这样将参数通过管道传递给我的脚本:

echo "file2.md" | .myscript.js --f1 file1.md

就比较 file1.mdfile2.md 而言,此方法有效,我将 pipe-argsyargs 结合使用以达到此目的。但是当涉及到提示时,管道参数会干扰并阻止它们工作。

我试过将它放在我的脚本之外并单独测试它,同时使用 prompt-syncinquirer 并将参数传递给脚本似乎也会影响提示。

所以我现在很确定这不是特定的提示包。


重新创建:

这是我的提示同步测试(名为 prompt-sync-test.js 的文件):

#!/usr/bin/env node
const prompt = require("prompt-sync")({"sigint": true})

for (var i = 0; i < 5; i++) {
  console.log("Going to bring up a prompt")
  var result = prompt("This is a test -- enter something >");
  console.log("Result", result)
}

...何时有效:

运行 ./prompt-sync-test.js 工作正常,每次打印结果都会问五个问题。

$ ./prompt-sync-test.js
Going to bring up a prompt
This is a test -- enter something >1
Result 1
Going to bring up a prompt
This is a test -- enter something >2
Result 2
Going to bring up a prompt
This is a test -- enter something >3
Result 3
Going to bring up a prompt
This is a test -- enter something >4
Result 4
Going to bring up a prompt
This is a test -- enter something >5
Result 5

...如果没有:

但是 运行 echo hello world | ./prompt-sync-test.js 会打印第一个提示的消息,但随后输入的任何输入都会再次重复提示消息,并输入任何先前的答案,就像这样(我正在输入与上述测试中的数字相同,并在每个数字后按回车键)...

$ echo hello world | ./prompt-test.
js
Going to bring up a prompt
This is a test -- enter something >1
This is a test -- enter something >1
                                     2
This is a test -- enter something >1
2
                                       3
This is a test -- enter something >1
2
3
                                         4
This is a test -- enter something >1
2
3
4
                                           5
This is a test -- enter something >1
2
3
4
5

将某些内容通过管道传输到我的脚本中似乎会干扰提示本身。

基本上,我希望能够使用我的脚本中通过管道输入的内容,但让提示符像第一种情况一样工作。我怎样才能做到这一点?

你可以在子 shell 之后使用 cat,像这样:

(echo "file2.md"; cat) | .myscript.js --f1 file1.md
(echo hello world; cat) | ./prompt-test.js

您还可以添加 exec 以减少一个过程:

(echo "file2.md"; exec cat) | .myscript.js --f1 file1.md
(echo hello world; exec cat) | ./prompt-test.js

也可以把cat放在外面,用-:

cat <(echo "file2.md") - | .myscript.js --f1 file1.md
cat <(echo hello world) - | ./prompt-test.js

我找到了一个使用包组合的解决方案,即 prompts and ttys

我切换到 prompts 因为它允许您为每个问题配置一个名为 stdin 的变量,这意味着您可以决定从哪里获取输入。

大多数提示包似乎默认使用 process.stdin 作为输入。这通常很好,但是当您将数据通过管道传输到命令中时,process.stdin 被管道占用,因此我之前遇到了问题。但是,如果您知道 process.stdin 被管道占用,您仍然可以从用户那里获得键盘输入。

这就是 ttys 的用武之地。这是一个非常简单的包,用于检查管道是否已被使用。

我几乎可以使用以下脚本重现我在问题中概述的成功结果——唯一缺少的是预提示消息 (Going to bring up a prompt)。我添加了 pipe-args 和 yargs 以显示管道输入的数据已保留。

#!/usr/bin/env node
const prompts = require("prompts");
const tty = require("tty");
const pipe = require("pipe-args").load();
const argv = require("yargs").argv;
const ttys = require("ttys");

const questions = [0, 1, 2, 3, 4]
  .map(x => ({
    type: "text",
    name: `prompt-${x}`,
    message: "This is a test -- enter something",
    stdin: ttys.stdin
  }));


const onSubmit = function (prompt, answer) {
  console.log("Result", answer); // => { value: 24 }
};

(async () => {
  const response = await prompts(questions, { onSubmit });
  console.log(argv);
  ttys.stdin.destroy();
})();