例如,我的脚本将使用process.stdout.write()
生成大量输出。我知道我可以通过less
运行它来将它们导入node mycode.js | less -N
。
但有没有办法让我可以在我的代码中进行管道处理,以便其他人可以正常运行我的代码node mycode.js
并仍然将我的输出传输到less
?
答案 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 atry/catch
之类的便利)中。这样,如果它无法安装在用户的系统上,您的代码仍会按预期运行,只是没有寻呼机的精确性。
答案 2 :(得分:0)
在节点的内置child_process
中的四个API中,您可能希望使用spawn
,这使您可以选择在调用脚本的当前shell中运行less
。所有其他选择,例如exec
,fork
都将仅启动一个新的不可见外壳。
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的全面视图。