【问题标题】:Running bash script from Deno从 Deno 运行 bash 脚本
【发布时间】:2021-07-19 02:28:05
【问题描述】:

假设我有这个超级有用且高级的 bash 脚本:

#!/usr/bin/env bash

echo What is your name?
read name
echo What is your age?
read age

当我尝试使用这样的简单脚本从 Deno 运行它时:

const process = Deno.run({
  cmd: [`./bash.sh`],
  stdin: "piped",
  stdout: "piped",
});

const decoder = new TextDecoder();

const output = await process.output()
const parsed = decoder.decode(output);

console.log(parsed);

它什么也不返回,但是如果我将 Deno 脚本简化为 bash 脚本的第一行,它会返回输出就好了

const process = Deno.run({
  cmd: [`echo`, `What is your name?`],
  stdin: "piped",
  stdout: "piped",
});

const decoder = new TextDecoder();

const output = await process.output()
const parsed = decoder.decode(output);

console.log(parsed);

这是为什么?我假设由于 bash 文件的开头和单行命令都以 echo 开头,所以它会两次返回相同的结果

【问题讨论】:

  • 您的代码在哪里向进程的标准输入(它期望从中读取的管道)提供任何内容?如果没有标准输入,reads 将永远不会完成。 (如果您至少关闭标准输入,它们会立即失败而不是挂起)。
  • 顺便说一句,请注意,不能保证没有 shebang 的脚本完全可以运行。如果您希望它被视为 bash 脚本(而不是 sh 脚本),那么 shebang 应该是 #!/usr/bin/env bash#!/usr/bin/bash 等。 (典型的 shell 具有后备行为,他们假设没有 shebang 的脚本是某种 shell 脚本,但是当某些东西在没有 shell 的情况下运行时,该后备不可用,因为操作系统的 execve 系统调用仅适用于操作系统内核的东西知道如何执行)。
  • @CharlesDuffy 我认为echo 可以用于输入标准输入。我的 bash 脚本中有 shebang 但忘记复制和粘贴它,我已经更新了代码 :)
  • echo 转到脚本的标准输出。这里没有任何东西将它循环回脚本自己的标准输入。 (如果程序的标准输入和标准输出自动相互连接,那将......不是很有用;通常,脚本的目标是从位置 A 获取输入并将输出发送到位置 B;如果有任何东西发送到位置-B 回到地方-A,实际上无法从脚本外部获取输入,也无法将输出发送到脚本外部)。
  • 让我们备份一下:您希望reads 从哪里获得输入?当你说stdin: "piped" 时,你是在告诉 Deno,你将负责编写输入该输入的 javascript 代码。如果您不想这样做,则不应传递该参数。

标签: bash deno


【解决方案1】:

1.5 版 deno added the prompt 函数允许您完全消除对不同程序的脱壳和通过 stdin/stdout 处理进程间通信的需要。

let name: string | null = null;
let age: string | null = null;

while (name === null) {
  name = prompt("What is your name?");
}

while (age === null) {
  age = prompt("What is your age?");
}

console.log(`you are ${name}, ${age}yo`);

【讨论】:

  • 我很欣赏这个答案,但我只是想弄清楚为什么我无法捕获echo,这就是为什么我编写了简单的 bash 脚本来展示我的挣扎:)
【解决方案2】:

您的代码告诉 Deno 将子进程设置为期望管道标准输入——但永远不要在标准输入上提供任何内容!因此,它挂在第一个read

如果我们把它拿出来(让标准输入从父进程传递),并且实际上回答了父进程标准输入上的两个提示,一切都会完美:

deno run --allow-run run-bash.js <<'EOF'
A Nony Mouse
3
EOF

...run-bash.js 包含:

const process = Deno.run({
  cmd: [`./bash.sh`],
  stdout: "piped",
});

const decoder = new TextDecoder();

const output = await process.output()
const parsed = decoder.decode(output);

console.log(parsed);

...和你的bash.sh 不变。 output 因此捕获两个提示(What is your name?What is your age?),并按要求将它们转发到 javascript 解释器的标准输出。

【讨论】:

  • 顺便说一句,打算发送给用户的提示通常应该发送到标准错误,而不是标准输出。这就是 bash 本身提示的地方,f/e。 stderr 是无缓冲的,而 stdout 默认情况下是行缓冲或块缓冲,具体取决于它是否要发送到 TTY。
  • ...因此,如果您的目标是提示用户,从他们那里读取数据,并写入要由 JavaScript 程序读取的数据,我希望编写提示到 stderr,以及要写入 stdout 的数据(以任何最终形式)。
【解决方案3】:

您必须致电 bash 才能调用您的脚本 (当然有--allow-run 选项) 喜欢:

const process = Deno.run({
  cmd: ["bash","bash.sh"],
  stdin: "piped",
  stdout: "piped",
});

const decoder = new TextDecoder();

const output = await process.output()
const parsed = decoder.decode(output);

console.log(parsed);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-04
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2013-03-14
    • 2011-05-10
    • 2013-06-24
    相关资源
    最近更新 更多