shell脚本spawn_如何使用child_process.spawn将Python / Ruby / PHP Shell脚本与Node.js集成
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.spawn
和child_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 sp
awn call from another part of your application.实际调用它的IIFE(“立即调用的函数表达式”),
(async () => { await run() }
)()。 这IIFE是一个很好的模式能够通过异步/的await(S EE异步JS:历史,模式和gotc有),但它只是在那里用于说明目的,因为它代表了调用wrapped 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返回的实例具有stdout
和stderr
事件发射器,因此我们可以使用.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
来解析与调用spawn
JavaScript文件/ 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中。 这使我们可以决定何时resolve
或reject
。
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 reso
lve/rej
ect the Promise’s value(s) from the Python/Ruby/other script.
我们还使用spawn().on('exit', (code, signal) => { /* probably call resolve() */
})为'exit'
添加了一个侦听器。 这是我们往往会to reso
升ve/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集成相关推荐
- Gestalt - 在浏览器里用 python/ruby 写客户端脚本
Gestalt 是 Mix Online Lab 创造出来的一个框架,利用它我们可以在浏览器里用 python/ruby 写脚本来操纵 DHTML 的各种对象,其作用就跟 javascript 类似. ...
- python执行shell命令行_python执行命令行:python中执行shell命令行read结果
+++++++++++++++++++++++++++++ python执行shell命令 1 os.system (只有这个方法是边执行边输出,其他方法是最后一次性输出) 可以返回运行shell命 ...
- python调用adb shell命令_如何在python脚本里面连续执行adb shell后面的各种命令
如何在python脚本里面连续执行adb shell后面的各种命令 adb shell "cd /data/local && mkdir tmp" adb shel ...
- linux脚本红包,利用adb shell和node.js实现抖音自动抢红包功能(推荐)
逻辑很简单,在抖音视频播完之后如果是红包视频,会跳出红包. 我们模拟逻辑如下: 点击屏幕中央,如果有红包打开红包,没有红包则暂停视频. 点击返回按钮,如果有红包关闭红包界面,没有红包提示再按一次退出( ...
- python中执行shell脚本之subprocess模块
一. 最近subprocess使用背景和介绍 因为最近领导要求,在Python端调用大数据的shell脚本,所以需要用到Python来执行shell脚本, 因此需要查看下subprocess模块文档. ...
- shell for循环命令行_精心汇总的24道shell脚本面试题
虽然现在Python在运维工作中已经使用很普遍,但是很多企业在找Linux云计算工程师的时候还是会问到 shell 脚本的问题,它有助于你在工作环境中自动完成很多任务. 如下是一些面试过程中,经常会遇 ...
- node.js linux shell,bash – Node.js Shell脚本和参数
参见文档 here.它非常具体如何传递命令行参数.注意,你可以使用exec或spawn. spawn有一个特定的参数为命令行参数,而使用exec你只是传递参数作为命令字符串的一部分来执行. 直接从文档 ...
- python调用shell命令-Python怎么运行shell脚本
Python作为一门脚本语言,有时候需要与shell命令交互式使用,在Python中提供了很多的方法可以调用并执行shell脚本,本文介绍几个简单的方法. Python怎么运行shell脚本 一.os ...
- android脚本快捷方式,Android:如何创建主屏幕快捷方式启动shell脚本?
答案:您的问题的答案应该是GScript(开放源代码和"根除设备上的任何地方"),但是当脚本完成时,谁想要盯着该模态终端输出屏幕?详情如下. > SManager (free ...
最新文章
- 人社局计算机考试报名时间,内蒙古人社局:2016年下半年计算机软件水平考试报名时间通知...
- 孤军大作战!疯狂DIY 1U硬件防火墙实录(二)
- 《飞机大战》安卓游戏开发源码(三)
- javascript自定义startWith()和endWith()方法
- 免费的定时任务托管 clock.sh
- java 多线程基础(一)
- 资管运营BAND原创 | 他山之石:境外基金业绩报酬计算方法(二)
- 在Vue中使用Echarts绘制带图标的矩形树图
- java实现公式解析
- GitHub使用指南
- 为大众而写的程序员小说——从 简单易懂的现代魔法 说开去
- sysbench--实践--02--CPU测试
- python常见的数据类型形式化定义_详解:规整数据(Tidy Data)的理论与Python实践
- 微机原理与接口技术——A.微型计算机基础(4)
- (转)QQ在线客服代码
- 一文教你搞定PMOS管选型
- 你为何会有中年危机感?”40岁失业”是一个无法打破的魔咒吗?
- django进阶11 聚合查询 Q
- CSS pink老师教学笔记详解
- elasticsearch 安装的坑