【问题标题】:How to detect if a Node.js script is running through a shell pipe?如何检测 Node.js 脚本是否通过 shell 管道运行?
【发布时间】:2013-03-06 04:09:21
【问题描述】:

我的问题与此类似:How to detect if my shell script is running through a pipe?。不同之处在于我正在处理的 shell 脚本是用 Node.js 编写的。

假设我进入:

echo "foo bar" | ./test.js

那我怎样才能在test.js中得到"foo bar"的值呢?

我读过Unix and Node: Pipes and Streams,但这似乎只提供了一个异步解决方案(除非我弄错了)。我正在寻找一个同步的解决方案。此外,使用这种技术,检测脚本是否正在通过管道传输似乎不是很简单。

TL;DR 我的问题有两个:

  1. 如何检测 Node.js 脚本是否通过 shell 管道运行,例如echo "foo bar" | ./test.js?
  2. 如果是,如何读取 Node.js 中的管道值?

【问题讨论】:

  • 附带说明:如果您无法触摸原始脚本,但仍想获得类似的管道结果,请尝试:./test.js $(echo 'foo bar')

标签: bash node.js pipe


【解决方案1】:

事实证明process.stdin.isTTY 不可靠,因为您可以生成一个不是 TTY 的子进程。

我使用file descriptors 找到了更好的解决方案here

您可以通过这些功能测试您的程序是否通过管道输入或输出:

function pipedIn(cb) {
    fs.fstat(0, function(err, stats) {
        if (err) {
            cb(err)
        } else {
            cb(null, stats.isFIFO())
        }
    })
}

function pipedOut(cb) {
    fs.fstat(1, function(err, stats) {
        if (err) {
            cb(err)
        } else {
            cb(null, stats.isFIFO())
        }
    })
}

pipedIn((err, x) => console.log("in", x))
pipedOut((err, x) => console.log("out", x))

这里有一些测试证明它有效。

❯❯❯ node pipes.js
in false
out false
❯❯❯ node pipes.js | cat -
in false
out true
❯❯❯ echo 'hello' | node pipes.js | cat -
in true
out true
❯❯❯ echo 'hello' | node pipes.js
in true
out false
❯❯❯ node -p -e "let x = require('child_process').exec(\"node pipes.js\", (err, res) => console.log(res))"
undefined
in false
out false
❯❯❯ node -p -e "let x = require('child_process').exec(\"echo 'hello' | node pipes.js\", (err, res) => console.log(res))"
undefined
in true
out false
❯❯❯ node -p -e "let x = require('child_process').exec(\"echo 'hello' | node pipes.js | cat -\", (err, res) => console.log(res))"
undefined
in true
out true
❯❯❯ node -p -e "let x = require('child_process').exec(\"node pipes.js | cat -\", (err, res) => console.log(res))"
undefined
in false
out true

【讨论】:

    【解决方案2】:

    您需要像这样检查stdout(而不是像其他地方建议的stdin):

    if (process.stdout.isTTY) {
      // not piped
    } else {
      // piped
    }
    

    【讨论】:

    • 这不是相反的吗?即node foo.js | cat
    【解决方案3】:

    如果您需要在 bash 中使用 inline --eval 字符串通过管道导入 nodejs,cat 也可以:

    $ echo "Hello" | node -e "console.log(process.argv[1]+' pipe');" "$(cat)"
    # "Hello pipe"
    

    【讨论】:

      【解决方案4】:

      我刚刚为我的部分问题找到了一个更简单的答案。

      要快速同步地检测管道内容是否正在传递到 Node.js 中的当前脚本,请使用 process.stdin.isTTY 布尔值:

      $ node -p -e 'process.stdin.isTTY'
      true
      $ echo 'foo' | node -p -e 'process.stdin.isTTY'
      undefined
      

      因此,在脚本中,您可以执行以下操作:

      if (process.stdin.isTTY) {
        // handle shell arguments
      } else {
        // handle piped content (see Jerome’s answer)
      }
      

      我之前没有找到这个的原因是因为我正在查看 process 的文档,其中根本没有提到 isTTY。相反,它在the TTY documentation 中提到。

      【讨论】:

      • 不幸的是,这将在子进程中失败:node -p -e "require('child_process').exec(\"node -p -e 'process.stdin.isTTY'\", (err, res) => console.log('err:', err, 'res:', res))"
      • TTY 在某些情况下可能不可用(例如 Docker 容器在没有伪 tty 的情况下启动)并且检查 process.stdin.isTTY 将失败。
      • 该死的。对此我们有什么可以做的吗?对于 unix 程序来说,这似乎是一个相当简单的问题。
      • @Lacek 以什么方式失败?是process.stdin === undefined 还是什么? @maxlath 在节点 14 上对我有用
      • @CameronTacklind docker run -t --rm node node -pe 'process.stdin.isTTY' 返回truedocker run --rm node node -pe 'process.stdin.isTTY' 返回undefined。所以执行环境也会影响process.stdin.isTTYundefined 并不总是意味着节点进程是管道的。
      【解决方案5】:

      管道用于处理像“foo bar”这样的小输入,但也可以处理大文件。

      流 API 确保您可以开始处理数据,而无需等待大文件完全通过管道传输(这对速度和内存来说更好)。它这样做的方式是为您提供大量数据。

      管道没有同步 API。如果你真的想在做某事之前掌握整个管道输入,你可以使用

      注意:仅使用 node >= 0.10.0,因为该示例使用 stream2 API

      var data = '';
      function withPipe(data) {
         console.log('content was piped');
         console.log(data.trim());
      }
      function withoutPipe() {
         console.log('no content was piped');
      }
      
      var self = process.stdin;
      self.on('readable', function() {
          var chunk = this.read();
          if (chunk === null) {
              withoutPipe();
          } else {
             data += chunk;
          }
      });
      self.on('end', function() {
         withPipe(data);
      });
      

      测试

      echo "foo bar" | node test.js
      

      node test.js
      

      【讨论】:

      • node test.jsv10.16.0 中为我挂起
      猜你喜欢
      • 1970-01-01
      • 2010-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多