我可以将node.js脚本输出管道输入`less`而不输入`|跑的时候少吗?

时间:2014-04-18 01:48:31

标签: node.js bash

例如,我的脚本将使用process.stdout.write()生成大量输出。我知道我可以通过less运行它来将它们导入node mycode.js | less -N

但有没有办法让我可以在我的代码中进行管道处理,以便其他人可以正常运行我的代码node mycode.js并仍然将我的输出传输到less

3 个答案:

答案 0 :(得分:2)

是的,您可以通过普通child_process核心模块的API将节点程序的输出传输到输入中。然而,问题将是控制pty。如果您正在运行节点程序,它将控制pty而less将无法访问pty,因此通过键入命令与less进行交互将不起作用。 AFAIK(其他人可能比我更清楚)在你的节点程序中没有干净的方法来做这个,所以我只想编写一个包装shell脚本来完成它并调用它。

我在npm中找到的最接近的可能性是default-pager,但是从我的快速测试工具中,它似乎不起作用。 : - (

答案 1 :(得分:1)

如果您愿意使用已编译的扩展程序,则可以在Node中 。{/ 3}。

我几乎准确地完成了你想要node-kexec的任务,如下所示(原谅CoffeeScript):

page = (cb)->

   # If we reach this point in the code and $_PAGINATED is already set, then we've
   # successfully paginated the script and should now actually run the code meant
   # to be run *inside* a pager.
   if process.env['_PAGINATED']?
      return cb()

   # I use tricks like this to control the pager itself; they can be super-dirty,
   # though, and mutating shell-command lines without a *lot* of careful
   # invocation logic is generally a bad idea unless you have a good reason:
   pager = process.env.PAGER || 'less --chop-long-lines'
   pager = pager.replace /less(\s|$)/, 'less --RAW-CONTROL-CHARS$1'

   # I use this elsewhere in my code-base to override `term.columns` if it is
   # unset; because the pager often doesn't properly report terminal-width
   process.env['PAGINATED_COLUMNS'] = term.columns
   process.env['_PAGINATED'] = 'yes'

   # This is a horrible hack. Thanks, Stack Overflow.
   #    <https://stackoverflow.com/a/22827128>
   escapeShellArg = (cmd)-> "'" + cmd.replace(/\'/g, "'\\''") + "'"

   # This is how we *re-invoke* precisely the exact instructions that our script /
   # executable was originally given; in addition to ensuring that `process.argv`
   # is the same by doing this, `kexec` will already ensure that our replacement
   # inherits our `process.stdout` and etc.
   #
   # (These arguments are invoked *in a shell*, as in `"sh" "-c" ...`, by
   # `kexec()`!)
   params = process.argv.slice()
   params = params.map (arg)-> escapeShellArg arg
   params.push '|'
   params.push pager

   log.debug "!! Forking and exec'ing to pager: `#{pager}`"
   log.wtf "-- Invocation via `sh -c`:", params.join ' '

   kexec params.join ' '

这可以像你期望的那样简单地调用;像page(print_help_text)这样的东西(这就是我使用它的方式)。

还有一些显而易见的陷阱:它不会神奇地分叉你的程序调用它,它会重新执行整个程序直到它被调用的程度;因此,您需要确保在调用page()之前发生的任何事情都是确定性的;即,如果使用同一组命令行参数重新调用程序,则会发生相同的事情。 (这是一种方便,而不是魔术。)你可能还想确保导致page()的代码是幂等的,即在运行两次时没有任何不良的副作用。

(如果你想在不编译原生扩展的情况下这样做,请尝试使用Node核心来添加像Ruby这样的exec函数。:P

  

Nota bene:如果您决定这样做,请使用标准--[no-]pager标记进行配置。寻呼机可以很方便,但不是每个人都想使用它。

     

同样,请注意编译后的依赖会导致很多人遇到麻烦;就个人而言,我将kexec保留在package.json的{​​{1}},然后in my project's executable(或use a try/catch之类的便利)中。这样,如果它无法安装在用户的系统上,您的代码仍会按预期运行,只是没有寻呼机的精确性。

答案 2 :(得分:0)

在节点的内置child_process中的四个API中,您可能希望使用spawn,这使您可以选择在调用脚本的当前shell中运行less。所有其他选择,例如execfork都将仅启动一个新的不可见外壳。

const spawn = require("child_process").spawn;

spawn(`cat <<< "${yourOutputString}" | less -r`, {   // <<< read the *HERE* string to cat
                                                     // less -r specifies colored output
            stdio: 'inherit', // use the current shell for stdio
            shell: true
    });

现在,您只需使用node script.js即可调用脚本。

冗长的tutorial为您提供了child_process API的全面视图。