shell脚本spawn

There are occasions when running a Python/Ruby/PHP shell script from Node.js is necessary. This post looks at best practices around leveraging child_process.spawn to encapsulate this call in Node.js/JavaScript.

有时需要从Node.js运行Python / Ruby / PHP Shell脚本。 这篇文章探讨了围绕child_process.spawn将此调用封装在Node.js / JavaScript中的最佳实践。

The goal here is to have an interoperability layer between Node.js and an outside shell. This is a quick workaround if some other part of your system isn’t developed in JavaScript.

这里的目标是在Node.js和外部外壳之间具有一个互操作性层。 如果系统的其他部分未使用JavaScript开发,则这是一种快速的解决方法。

We’ll use spawn over exec because we’re talking about passing data and potentially large amounts of it. To understand the difference between child_process.spawn and child_process.exec see “Difference between spawn and exec of Node.js child_process”.

我们将在exec之上使用spawn ,因为我们正在谈论传递数据以及潜在的大量数据。 要了解child_process.spawnchild_process.exec之间的child_process.spawn ,请参阅“ Node.js child_process的spawn和exec之间的区别 ”。

The long and short of it is use exec for small amounts of data (under 200k) using a Buffer interface and spawn for larger amounts using a stream interface.

它的长处和spawn是通过Buffer接口使用exec来处理少量数据(200k以下),而使用stream接口使用exec来产生大量数据。

spawn has a more verbose syntax for some of the use-cases we’ll look at. It’s more serviceable for integrating with Ruby/Python/PHP since we might get more data than a couple of lines of text.

对于我们将要看到的一些用例, spawn具有更详细的语法。 与Ruby / Python / PHP集成时,它更具服务性,因为我们可能会获得比两行文本更多的数据。

Full examples github.com/HugoDF/node-run-python.

完整示例github.com/HugoDF/node-run-python 。

The following examples contain 2 sections:

以下示例包含2个部分:

  • The part that actually runs the shell command, usually a function called run, and

    实际运行shell命令的部分,通常是一个称为run的函数,以及

  • an IIFE (“immediately invoked function expression”) that actually calls it, (async () => { await run() })(). This IIFE is a nice pattern enabled by async/await (see Async JS: history, patterns and gotchas) but it’s just there for illustration purposes since it represents the call to the wrapped spawn call from another part of your application.

    实际调用它的IIFE(“立即调用的函数表达式”), (async () => { await run() } )()。 这IIFE是一个很好的模式能够通过异步/的await(S EE异步JS:历史,模式和gotc有),但它只是在那里用于说明目的,因为它代表了调用wrapp ed sp从应用程序的其他部分芒电话。

调用shell命令并记录它 (Call a shell command and log it)

Using spawn is overkill in this situation since echo is only going to return what’s passed to it.

在这种情况下,使用spawn会显得过大,因为echo只会返回传递给它的内容。

The example is pretty self-explanatory and shows how to use child_process.spawn to “shell out” and read that data back.

该示例是不言自明的,并说明了如何使用child_process.spawn进行“ shell out”并读回该数据。

spawn takes the executable to call as the first parameter and optionally an array of options/parameters for the executable as the second parameter.

spawn将可执行文件作为第一个参数,并将可选的选项/参数数组作为第二个参数。

const { spawn } = require('child_process');
function run() {const process = spawn('echo', ['foo']);process.stdout.on('data',(data) => console.log(data.toString()));
}
(() => {try {run()// process.exit(0)} catch (e) {console.error(e.stack);process.exit(1);}
})();

调用Python获取其版本 (Call Python for its version)

We’ll move quite quickly to showcase how we would do something similar to the above with Python. Note again how --version is passed inside of an array.

我们将很快采取行动,以展示我们如何使用Python进行与上述类似的操作。 再次注意--version如何在数组内部传递。

We also create a nice logger to differentiate between stdout and stderr and bind to them. Since spawn returns an instance which has stdout and stderr event emitters, we can bind our logOutput function to 'data' event using .on('data', () => { /* our callback function */ }).

我们还创建了一个不错的记录器,以区分stdout和stderr并绑定到它们。 由于spawn返回的实例具有stdoutstderr事件发射器,因此我们可以使用.on('data', () => { /* our callback function */ })将logOutput函数绑定到'data'事件。

Another interesting tidbit is that python --version outputs the version to stderr. The inconsistencies around whether *NIX executables use exit codes, stderr and stdout on success/error are a quirk that we’ll have to bear in mind while integrating Python/Ruby/other with Node.js.

另一个有趣的花絮是python --version将版本输出到stderr 。 * NIX可执行文件是否在成功/错误时使用退出代码,stderr和stdout不一致,这是在将Python / Ruby / other与Node.js集成时必须牢记的一个怪癖。

const { spawn } = require('child_process')
const logOutput = (name) => (data) => console.log(`[${name}] ${data.toString()}`)
function run() {const process = spawn('python', ['--version']);
process.stdout.on('data',logOutput('stdout'));
process.stderr.on('data',logOutput('stderr'));
}
(() => {try {run()process.exit(0)} catch (e) {console.error(e.stack);process.exit(1);}
})();

Output:

输出:

$ node run.js
[stderr] Python 2.7.13

从Node调用Python脚本 (Call a Python script from Node)

We’ll now run a fully-fledged Python script (although it could just as well be Ruby, PHP, shell etc.) from Node.js.

现在,我们将运行来自Node.js的成熟的Python脚本(尽管它也可以是Ruby,PHP,shell等)。

This is script.py, it just logs out argv (the “argument vector”, ie. ['path/to/executable', /* command line arguments ])

这是script.py ,它只是注销了argv (“参数向量”,即['path/to/executable', /* command line arguments ] )

import sys
print(sys.argv)

Like in the previous example, we’ll just call spawn with python with the path to the Python script (./script.py) in the second parameter.

像前面的示例一样,我们仅使用python调用spawn,并在第二个参数中使用Python脚本( ./script.py )的路径。

Here comes another gotcha of integrating scripts in this fashion. In this example, the path to the script is based on the working directory from which node is called.

这是以这种方式集成脚本的另一个难题。 在此示例中,脚本的路径基于从中调用node的工作目录。

There is a workaround, of course, using the path module and __dirname, which for example could resolve a other-script.py co-located with the JavaScript file/Node module calling spawn using: require('path').resolve(__dirname, './other-script.py').

当然,有一种解决方法,使用path模块和__dirname ,例如,可以使用以下other-script.py来解析与调用spawnJavaScript文件/ Node模块位于other-script.py位置的other-script.py require('path').resolve(__dirname, './other-script.py')

const { spawn } = require('child_process')
const logOutput = (name) => (data) => console.log(`[${name}] ${data.toString()}`)
function run() {const process = spawn('python', ['./script.py']);
process.stdout.on('data',logOutput('stdout'));
process.stderr.on('data',logOutput('stderr'));
}
(() => {try {run()// process.exit(0)} catch (e) {console.error(e.stack);process.exit(1);}
})();

Output:

输出:

node run.js
\[stdout\] ['./script.py']

使用child_process.spawn从Node.js将参数传递给Python脚本 (Pass arguments to a Python script from Node.js using child_process.spawn)

The next step of integration is to be able to pass data from the Node/JavaScript code to the Python script.

集成的下一步是能够将数据从Node / JavaScript代码传递到Python脚本。

In order to do this, we’ll just pass more shell arguments using the arguments array (the second parameter to spawn).

为了做到这一点,我们将使用arguments数组( spawn的第二个参数)传递更多的shell参数。

const { spawn } = require('child_process')
const logOutput = (name) => (data) => console.log(`[${name}] ${data.toString()}`)
function run() {const process = spawn('python', ['./script.py', 'my', 'args']);process.stdout.on('data',logOutput('stdout'));process.stderr.on('data',logOutput('stderr'));
}
(() => {try {run()// process.exit(0)} catch (e) {console.error(e.stack);process.exit(1);}
})();

Our script.py will also just log out the argv except for the first element (which is the path to the script).

除了第一个元素(这是脚本的路径)之外,我们的script.py还将注销argv

import sys
print(sys.argv)[1:]

Here’s the output:

这是输出:

node run.js
\[stdout\] ['my', 'args']

从Node.js读取child_process.spawn输出 (Read child_process.spawn output from Node.js)

It’s nice to be able to pass data down to the Python script. We’re still not able to get the data from the Python script back in a format that we’re able to leverage in our Node.js/JavaScript application.

能够将数据向下传递到Python脚本真是太好了。 我们仍然无法以能够在Node.js / JavaScript应用程序中利用的格式从Python脚本中获取数据。

The solution to this is to wrap the whole spawn -calling function into a Promise. This allows us to decide when we want to resolve or reject.

解决方案是将整个spawn calling函数包装到Promise中。 这使我们可以决定何时resolvereject

To keep track of the Python script’s output stream(s), we manually buffer the output using arrays (one for stdout and another for stderr).

为了跟踪Python脚本的输出流,我们使用数组(一个用于stdout ,另一个用于stderr )手动缓冲输出。

We also add a listener for 'exit' using spawn().on('exit', (code, signal) => { /* probably call resolve() */ }). This is where we will tend to resolve/reject the Promise’s value(s) from the Python/Ruby/other script.

我们还使用spawn().on('exit', (code, signal) => { /* probably call resolve() */ })为'exit'添加了一个侦听器。 这是我们往往会to resove/rej ECT从Python / Ruby的/其他脚本无极的值(一个或多个)。

const { spawn } = require('child_process')
const logOutput = (name) => (data) => console.log(`[${name}] ${data}`)
function run() {return new Promise((resolve, reject) => {const process = spawn('python', ['./script.py', 'my', 'args']);const out = []process.stdout.on('data',(data) => {out.push(data.toString());logOutput('stdout')(data);});const err = []process.stderr.on('data',(data) => {err.push(data.toString());logOutput('stderr')(data);});process.on('exit', (code, signal) => {logOutput('exit')(`${code} (${signal})`)resolve(out);});});
}
(async () => {try {const output = await run()logOutput('main')(output)process.exit(0)} catch (e) {console.error(e.stack);process.exit(1);}
})();

Output:

输出:

node run.js
\[stdout\] ['my', 'args']
\[main\] ['my', 'args']

处理来自child_process.spawn的错误 (Handle errors from child_process.spawn)

Next up we need to handle errors from the Python/Ruby/shell script at the Node.js/JavaScript level.

接下来,我们需要在Node.js / JavaScript级别处理来自Python / Ruby / shell脚本的错误。

The main way that a *NIX executable signals that it errored are by using a 1 exit code. That’s why the .on('exit' handler now does a check against code === 0 before deciding whether to resolve or reject with value(s).

* NIX可执行文件发出错误信号的主要方式是使用1退出代码。 这就是为什么.on('exit'处理程序现在在确定是使用值解析还是拒绝之前,对code === 0进行检查。

const { spawn } = require('child_process')
const logOutput = (name) => (data) => console.log(`[${name}] ${data}`)
function run() {return new Promise((resolve, reject) => {const process = spawn('python', ['./script.py', 'my', 'args']);
const out = []process.stdout.on('data',(data) => {out.push(data.toString());logOutput('stdout')(data);});
const err = []process.stderr.on('data',(data) => {err.push(data.toString());logOutput('stderr')(data);});
process.on('exit', (code, signal) => {logOutput('exit')(`${code} (${signal})`)if (code === 0) {resolve(out);} else {reject(new Error(err.join('\n')))}});});
}
(async () => {try {const output = await run()logOutput('main')(output)process.exit(0)} catch (e) {console.error('Error during script execution ', e.stack);process.exit(1);}
})();

Output:

输出:

node run.js
[stderr] Traceback (most recent call last):File "./script.py", line 3, in <module>print(sy.argv)[1:]
NameError: name 'sy' is not defined
Error during script execution Error: Traceback (most recent call last):File "./script.py", line 3, in <module>print(sy.argv)[1:]
NameError: name 'sy' is not defined
at ChildProcess.process.on (/app/run.js:33:16)at ChildProcess.emit (events.js:182:13)at Process.ChildProcess._handle.onexit (internal/child_process.js:240:12)

将结构化数据从Python / Ruby传递到Node.js / JavaScript (Pass structured data from Python/Ruby to Node.js/JavaScript)

The final step to full integration between Ruby/Python/PHP/shell scripts and our Node.js/JavaScript application layer is to be able to pass structured data back from the script up to Node.js/JavaScript.

在Ruby / Python / PHP / shell脚本与Node.js / JavaScript应用程序层之间进行完全集成的最后一步是能够将结构化数据从脚本传递回Node.js / JavaScript。

The simplest structured data format that tends to be available in both Python/Ruby/PHP and Node.js/JavaScript is JSON.

易于在Python / Ruby / PHP和Node.js / JavaScript中使用的最简单的结构化数据格式是JSON。

In the Python script, we print the json.dumps() output of a dictionary, see script.py:

在Python脚本中,我们打印字典的json.dumps()输出,请参阅script.py

import sys
import json
send_message_back = {'arguments': sys.argv[1:],'message': """Hello,
This is my message.
To the world"""
}
print(json.dumps(send_message_back))

In Node, we add some JSON-parsing logic (using JSON.parse) in the 'exit' handler.

在Node中,我们在'exit'处理程序中添加了一些JSON解析逻辑(使用JSON.parse )。

A gotcha at this point is if, for example JSON.parse() fails due to badly-formed JSON, we need to propagate that error up. Hence the try/catch where the catch clause reject-s the potential error: try { resolve(JSON.parse(out[0])) } catch(e) { reject(e) }.

此时的一个陷阱是,例如,如果JSON.parse()由于JSON.parse()不正确的JSON而失败,则我们需要将该错误传播出去。 因此,在try / catch中catch子句reject -s的潜在错误是: try { resolve(JSON.parse(out[0])) } catch(e) { reject(e) }

const { spawn } = require('child_process')
const logOutput = (name) => (message) => console.log(`[${name}] ${message}`)
function run() {return new Promise((resolve, reject) => {const process = spawn('python', ['./script.py', 'my', 'args']);const out = []process.stdout.on('data',(data) => {out.push(data.toString());logOutput('stdout')(data);});const err = []process.stderr.on('data',(data) => {err.push(data.toString());logOutput('stderr')(data);});process.on('exit', (code, signal) => {logOutput('exit')(`${code} (${signal})`)if (code !== 0) {reject(new Error(err.join('\n')))return}try {resolve(JSON.parse(out[0]));} catch(e) {reject(e);}});});
}
(async () => {try {const output = await run()logOutput('main')(output.message)process.exit(0)} catch (e) {console.error('Error during script execution ', e.stack);process.exit(1);}
})();

Output:

输出:

node run.js
[stdout] {"message": "Hello,\nThis is my message.\n\nTo the world", "arguments": ["my", "args"]}
[main] Hello,
This is my message.
To the world

That’s it! Thanks for reading :)

而已! 谢谢阅读 :)

I’ve got mentoring spots open at https://mentorcruise.com/mentor/HugoDiFrancesco/. Do that if you want Node.js/JavaScript/career mentoring or feel free to tweet at me @hugo__df

我可以在https://mentorcruise.com/mentor/HugoDiFrancesco/上找到指导站点 。 如果您想要Node.js / JavaScript / career指导,或者随时在@hugo__df上向我发推文,请执行此操作

And read more of my articles on codewithhugo.com

并在codewithhugo.com上阅读我的更多文章

翻译自: https://www.freecodecamp.org/news/how-to-integrate-a-python-ruby-php-shell-script-with-node-js-using-child-process-spawn-e26ca3268a11/

shell脚本spawn

shell脚本spawn_如何使用child_process.spawn将Python / Ruby / PHP Shell脚本与Node.js集成相关推荐

  1. Gestalt - 在浏览器里用 python/ruby 写客户端脚本

    Gestalt 是 Mix Online Lab 创造出来的一个框架,利用它我们可以在浏览器里用 python/ruby 写脚本来操纵 DHTML 的各种对象,其作用就跟 javascript 类似. ...

  2. python执行shell命令行_python执行命令行:python中执行shell命令行read结果

    +++++++++++++++++++++++++++++ python执行shell命令 1 os.system  (只有这个方法是边执行边输出,其他方法是最后一次性输出) 可以返回运行shell命 ...

  3. python调用adb shell命令_如何在python脚本里面连续执行adb shell后面的各种命令

    如何在python脚本里面连续执行adb shell后面的各种命令 adb shell "cd /data/local && mkdir tmp" adb shel ...

  4. linux脚本红包,利用adb shell和node.js实现抖音自动抢红包功能(推荐)

    逻辑很简单,在抖音视频播完之后如果是红包视频,会跳出红包. 我们模拟逻辑如下: 点击屏幕中央,如果有红包打开红包,没有红包则暂停视频. 点击返回按钮,如果有红包关闭红包界面,没有红包提示再按一次退出( ...

  5. python中执行shell脚本之subprocess模块

    一. 最近subprocess使用背景和介绍 因为最近领导要求,在Python端调用大数据的shell脚本,所以需要用到Python来执行shell脚本, 因此需要查看下subprocess模块文档. ...

  6. shell for循环命令行_精心汇总的24道shell脚本面试题

    虽然现在Python在运维工作中已经使用很普遍,但是很多企业在找Linux云计算工程师的时候还是会问到 shell 脚本的问题,它有助于你在工作环境中自动完成很多任务. 如下是一些面试过程中,经常会遇 ...

  7. node.js linux shell,bash – Node.js Shell脚本和参数

    参见文档 here.它非常具体如何传递命令行参数.注意,你可以使用exec或spawn. spawn有一个特定的参数为命令行参数,而使用exec你只是传递参数作为命令字符串的一部分来执行. 直接从文档 ...

  8. python调用shell命令-Python怎么运行shell脚本

    Python作为一门脚本语言,有时候需要与shell命令交互式使用,在Python中提供了很多的方法可以调用并执行shell脚本,本文介绍几个简单的方法. Python怎么运行shell脚本 一.os ...

  9. android脚本快捷方式,Android:如何创建主屏幕快捷方式启动shell脚本?

    答案:您的问题的答案应该是GScript(开放源代码和"根除设备上的任何地方"),但是当脚本完成时,谁想要盯着该模态终端输出屏幕?详情如下. > SManager (free ...

最新文章

  1. 人社局计算机考试报名时间,内蒙古人社局:2016年下半年计算机软件水平考试报名时间通知...
  2. 孤军大作战!疯狂DIY 1U硬件防火墙实录(二)
  3. 《飞机大战》安卓游戏开发源码(三)
  4. javascript自定义startWith()和endWith()方法
  5. 免费的定时任务托管 clock.sh
  6. java 多线程基础(一)
  7. 资管运营BAND原创 | 他山之石:境外基金业绩报酬计算方法(二)
  8. 在Vue中使用Echarts绘制带图标的矩形树图
  9. java实现公式解析
  10. GitHub使用指南
  11. 为大众而写的程序员小说——从 简单易懂的现代魔法 说开去
  12. sysbench--实践--02--CPU测试
  13. python常见的数据类型形式化定义_详解:规整数据(Tidy Data)的理论与Python实践
  14. 微机原理与接口技术——A.微型计算机基础(4)
  15. (转)QQ在线客服代码
  16. 一文教你搞定PMOS管选型
  17. 你为何会有中年危机感?”40岁失业”是一个无法打破的魔咒吗?
  18. django进阶11 聚合查询 Q
  19. CSS pink老师教学笔记详解
  20. elasticsearch 安装的坑

热门文章

  1. SpringBoot—数据库初始化脚本配置
  2. QT 连接 sql server数据库 完整演示
  3. 作业 利用单选框控制图片的显示
  4. 190906描述笔记
  5. 字符串、文件操作,英文词率统计预处理
  6. Spring Cloud Zuul中使用Swagger汇总API接口文档 1
  7. ABP理论学习之日志记录
  8. 初学者指南:服务器基本技术名词
  9. if和switch以及for
  10. Windows下Redmine插件安装