目錄
前言
node執行bash腳本: 勉強解決方案:child_process API
zx函式庫
$`command`
cd()
fetch()
question()
sleep()
nothrow()
chalk
fs
os
$.shell
$.quote
传递环境变量
传递数组
首頁 web前端 js教程 淺談nodejs執行bash腳本的幾種方案

淺談nodejs執行bash腳本的幾種方案

Jul 08, 2021 am 11:12 AM
bash腳本 nodejs

nodejs如何執行bash腳本?本篇文章為大家介紹node執行bash腳本的幾種方案。

淺談nodejs執行bash腳本的幾種方案

前言

最近在學習bash腳本語法,但如果對bash語法不是熟手的話,感覺非常容易出錯,比如說:顯示未定義的變數shell中變數沒有定義,仍然是可以使用的,但是它的結果可能不是你所預期的。舉個例子:

#!/bin/bash

# 这里是判断变量var是否等于字符串abc,但是var这个变量并没有声明
if [ "$var" = "abc" ] 
then
   # 如果if判断里是true就在控制台打印 “ not abc”
   echo  " not abc" 
else
   # 如果if判断里是false就在控制台打印 “ abc”
   echo " abc "
fi
登入後複製

結果是列印了abc,但問題是,這個腳本應該要報錯啊,變數並沒有賦值算是錯誤吧。

為了彌補這些錯誤,我們學會在腳本開頭加入:set -u這句指令的意思是腳本在頭部加上它,遇到不存在的變數就會報錯,並停止執行。

再運行就會提示:test.sh: 3: test.sh: num: parameter not set

再想像一下,你本來想刪除:rm -rf $dir /*然後dir是空的時候,變成了什麼? rm -rf是刪除指令,$dir是空的話,相當於執行 rm -rf /*,這是刪除所有檔案和資料夾。 。 。然後,你的系統就沒了,這就是傳說中的刪庫跑路嗎~~~~

如果是node或是瀏覽器環境,我們直接var = == 'abc' 肯定是會報錯的,也就是說很多javascript程式設計經驗無法復用到bash來,如果能復用的話,該多好啊。

後來就開始探索,如果用node腳本代替bash該多好啊,經過一天折騰逐漸發現一個神器,Google旗下的zx庫,先別著急,我先不介紹這個庫,我們先看看目前主流用node如何寫bash腳本,就知道為啥它是神器了。

node執行bash腳本: 勉強解決方案:child_process API

例如child_process的API裡面exec指令

const { exec } = require("child_process");

exec("ls -la", (error, stdout, stderr) => {
    if (error) {
        console.log(`error: ${error.message}`);
        return;
    }
    if (stderr) {
        console.log(`stderr: ${stderr}`);
        return;
    }
    console.log(`stdout: ${stdout}`);
});
登入後複製

這裡要注意的是,首先exec是異步的,但是我們bash腳本指令很多都是同步的。

而且注意:error物件不同於stderr. errorchild_process模組無法執行指令時,該對象不為空。例如,查找一個文件找不到該文件,則error物件不為空。但是,如果命令成功運行並將訊息寫入標準錯誤流,則該stderr物件不會為空。

當然我們可以使用同步的exec指令,execSync

// 引入 exec 命令 from child_process 模块
const { execSync } = require("child_process");

// 同步创建了一个hello的文件夹
execSync("mkdir hello");
登入後複製

再簡單介紹一下child_process的其它能夠執行bash指令的api

  • spawn: 啟動子程序來執行指令
  • exec:啟動子程序來執行指令,與spawn不同的是,它有一個回呼函式能知道子程序的狀況
  • execFile:啟動一子程序來執行可執行檔
  • fork:與spawn類似,不同點是它需要指定子程序需要執行的javascript檔
# #exec跟ececFile不同的是,exec適合執行指令,eexecFile適合執行檔。

【推薦學習:《

nodejs 教學》】

#node執行bash腳本: 進階方案shelljs
const shell = require('shelljs');
 
# 删除文件命令
shell.rm('-rf', 'out/Release');
// 拷贝文件命令
shell.cp('-R', 'stuff/', 'out/Release');
 
# 切换到lib目录,并且列出目录下到.js结尾到文件,并替换文件内容(sed -i 是替换文字命令)
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
  shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
  shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
  shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
 
# 除非另有说明,否则同步执行给定的命令。 在同步模式下,这将返回一个 ShellString
#(与 ShellJS v0.6.x 兼容,它返回一个形式为 { code:..., stdout:..., stderr:... } 的对象)。
# 否则,这将返回子进程对象,并且回调接收参数(代码、标准输出、标准错误)。
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
  shell.echo('Error: Git commit failed');
  shell.exit(1);
}
登入後複製

#從上面程式碼看來,shelljs真的已經算是非常棒的nodejs寫bash腳本的方案了,如果你們那邊的node環境不能隨便升級,我覺得shelljs確實夠用了。

接著我們看看今天的主角zx,start已經17.4k了。

zx函式庫

官方網址:https://www.npmjs.com/package/zx

我們先來看看怎麼用

#!/usr/bin/env zx

await $`cat package.json | grep name`

let branch = await $`git branch --show-current`
await $`dep deploy --branch=${branch}`

await Promise.all([
  $`sleep 1; echo 1`,
  $`sleep 2; echo 2`,
  $`sleep 3; echo 3`,
])

let name = 'foo bar'
await $`mkdir /tmp/${name}
登入後複製
登入後複製

各位看官覺得咋樣,是不是就是在寫linux指令而已,bash語法可以忽略很多,直接上js就行,而且它的優點還不止這些,有一些特點挺有意思的:

1、支援ts,自動編譯.ts為.mjs文件,.mjs檔案是node高版自帶的支援es6 module的檔案結尾,也就是這個檔案直接import模組就行,不用其它工具轉義

2、自備支援管道操作pipe方法

3、自備fetch庫,可以進行網路請求,自備chalk庫,可以列印有顏色的字體,自備錯誤處理nothrow方法,如果bash命令出錯,可以包裹在這個方法裡忽略錯誤

完整中文文檔(在下翻譯水平一般,請見諒)
#!/usr/bin/env zx

await $`cat package.json | grep name`

let branch = await $`git branch --show-current`
await $`dep deploy --branch=${branch}`

await Promise.all([
  $`sleep 1; echo 1`,
  $`sleep 2; echo 2`,
  $`sleep 3; echo 3`,
])

let name = 'foo bar'
await $`mkdir /tmp/${name}
登入後複製
登入後複製

Bash 很棒,但是在在編寫腳本時,人們通常會選擇更方便的程式語言。 JavaScript 是一個完美的選擇,但標準的 Node.js 程式庫在使用之前需要額外的做一些事情。 zx 是基於 child_process ,轉義參數並提供合理的預設值。

安裝

npm i -g zx
登入後複製

需要的環境

Node.js >= 14.8.0
登入後複製

将脚本写入扩展名为 .mjs 的文件中,以便能够在顶层使用await

将以下 shebang添加到 zx 脚本的开头:

#!/usr/bin/env zx
现在您将能够像这样运行您的脚本:

chmod +x ./script.mjs
./script.mjs
登入後複製

或者通过 zx可执行文件:

zx ./script.mjs
登入後複製

所有函数($、cd、fetch 等)都可以直接使用,无需任何导入。

$`command`

使用 child_process 包中的 spawn 函数执行给定的字符串, 并返回 ProcessPromise.

let count = parseInt(await $`ls -1 | wc -l`)
console.log(`Files count: ${count}`)
登入後複製

例如,要并行上传文件:

如果执行的程序返回非零退出代码,ProcessOutput 将被抛出

try {
  await $`exit 1`
} catch (p) {
  console.log(`Exit code: ${p.exitCode}`)
  console.log(`Error: ${p.stderr}`)
}
登入後複製

ProcessPromise,以下是promise typescript的接口定义

class ProcessPromise<T> extends Promise<T> {
  readonly stdin: Writable
  readonly stdout: Readable
  readonly stderr: Readable
  readonly exitCode: Promise<number>
  pipe(dest): ProcessPromise<T>
}
登入後複製

pipe() 方法可用于重定向标准输出:

await $`cat file.txt`.pipe(process.stdout)
登入後複製

阅读更多的关于管道的信息:https://github.com/google/zx/blob/HEAD/examples/pipelines.md

ProcessOutputtypescript接口定义

class ProcessOutput {
  readonly stdout: string
  readonly stderr: string
  readonly exitCode: number
  toString(): string
}
登入後複製

函数:

cd()

更改当前工作目录

cd(&#39;/tmp&#39;)
await $`pwd` // outputs /tmp
登入後複製

fetch()

node-fetch 包。

let resp = await fetch(&#39;http://wttr.in&#39;)
if (resp.ok) {
  console.log(await resp.text())
}
登入後複製

question()

readline包

let bear = await question(&#39;What kind of bear is best? &#39;)
let token = await question(&#39;Choose env variable: &#39;, {
  choices: Object.keys(process.env)
})
登入後複製

在第二个参数中,可以指定选项卡自动完成的选项数组

以下是接口定义

function question(query?: string, options?: QuestionOptions): Promise<string>
type QuestionOptions = { choices: string[] }
登入後複製

sleep()

基于setTimeout 函数

await sleep(1000)
登入後複製

nothrow()

将 $ 的行为更改, 如果退出码不是0,不跑出异常.

ts接口定义

function nothrow<P>(p: P): P
登入後複製
await nothrow($`grep something from-file`)
// 在管道内:

await $`find ./examples -type f -print0`
  .pipe(nothrow($`xargs -0 grep something`))
  .pipe($`wc -l`)
登入後複製

以下的包,无需导入,直接使用

chalk

console.log(chalk.blue(&#39;Hello world!&#39;))
登入後複製

fs

类似于如下的使用方式

import {promises as fs} from &#39;fs&#39;
let content = await fs.readFile(&#39;./package.json&#39;)
登入後複製

os

await $`cd ${os.homedir()} && mkdir example`
登入後複製

配置:

$.shell

指定要用的bash.

$.shell = &#39;/usr/bin/bash&#39;
登入後複製

$.quote

指定用于在命令替换期间转义特殊字符的函数

默认用的是 shq 包.

注意:

__filename & __dirname这两个变量是在commonjs中的。我们用的是.mjs结尾的es6 模块。

ESM模块中,Node.js 不提供__filename __dirname 全局变量。 由于此类全局变量在脚本中非常方便,因此 zx 提供了这些以在 .mjs 文件中使用(当使用 zx 可执行文件时)

require也是commonjs中的导入模块方法, 在 ESM 模块中,没有定义 require() 函数。zx提供了 require() 函数,因此它可以与 .mjs 文件中的导入一起使用(当使用 zx 可执行文件时)

传递环境变量

process.env.FOO = &#39;bar&#39;await $`echo $FOO`
登入後複製

传递数组

如果值数组作为参数传递给 $,数组的项目将被单独转义并通过空格连接 Example:

let files = [1,2,3]await $`tar cz ${files}`
登入後複製

可以通过显式导入来使用 $ 和其他函数

#!/usr/bin/env nodeimport {$} from &#39;zx&#39;await $`date`复制代码
登入後複製

zx 可以将 .ts 脚本编译为 .mjs 并执行它们

zx examples/typescript.ts
登入後複製

更多编程相关知识,请访问:编程视频!!

以上是淺談nodejs執行bash腳本的幾種方案的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1322
25
PHP教程
1269
29
C# 教程
1249
24
nodejs和vuejs區別 nodejs和vuejs區別 Apr 21, 2024 am 04:17 AM

Node.js 是一種伺服器端 JavaScript 執行時,而 Vue.js 是一個客戶端 JavaScript 框架,用於建立互動式使用者介面。 Node.js 用於伺服器端開發,如後端服務 API 開發和資料處理,而 Vue.js 用於用戶端開發,如單一頁面應用程式和響應式使用者介面。

nodejs是後端框架嗎 nodejs是後端框架嗎 Apr 21, 2024 am 05:09 AM

Node.js 可作為後端框架使用,因為它提供高效能、可擴展性、跨平台支援、豐富的生態系統和易於開發等功能。

nodejs中的全域變數有哪些 nodejs中的全域變數有哪些 Apr 21, 2024 am 04:54 AM

Node.js 中存在以下全域變數:全域物件:global核心模組:process、console、require執行階段環境變數:__dirname、__filename、__line、__column常數:undefined、null、NaN、Infinity、-Infinity

nodejs怎麼連接mysql資料庫 nodejs怎麼連接mysql資料庫 Apr 21, 2024 am 06:13 AM

要連接 MySQL 資料庫,需要遵循以下步驟:安裝 mysql2 驅動程式。使用 mysql2.createConnection() 建立連接對象,其中包含主機位址、連接埠、使用者名稱、密碼和資料庫名稱。使用 connection.query() 執行查詢。最後使用 connection.end() 結束連線。

nodejs安裝目錄裡的npm與npm.cmd檔有什麼差別 nodejs安裝目錄裡的npm與npm.cmd檔有什麼差別 Apr 21, 2024 am 05:18 AM

Node.js 安裝目錄中有兩個與 npm 相關的文件:npm 和 npm.cmd,區別如下:擴展名不同:npm 是可執行文件,npm.cmd 是命令視窗快捷方式。 Windows 使用者:npm.cmd 可以在命令提示字元中使用,npm 只能從命令列執行。相容性:npm.cmd 特定於 Windows 系統,npm 跨平台可用。使用建議:Windows 使用者使用 npm.cmd,其他作業系統使用 npm。

nodejs是後端開發語言嗎 nodejs是後端開發語言嗎 Apr 21, 2024 am 05:09 AM

是的,Node.js 是一種後端開發語言。它用於後端開發,包括處理伺服器端業務邏輯、管理資料庫連接和提供 API。

nodejs可以寫前端嗎 nodejs可以寫前端嗎 Apr 21, 2024 am 05:00 AM

是的,Node.js可用於前端開發,主要優勢包括高效能、豐富的生態系統和跨平台相容性。需要考慮的注意事項有學習曲線、工具支援和社群規模較小。

nodejs和java的差別大嗎 nodejs和java的差別大嗎 Apr 21, 2024 am 06:12 AM

Node.js 和 Java 的主要差異在於設計和特性:事件驅動與執行緒驅動:Node.js 基於事件驅動,Java 基於執行緒驅動。單執行緒與多執行緒:Node.js 使用單執行緒事件循環,Java 使用多執行緒架構。執行時間環境:Node.js 在 V8 JavaScript 引擎上運行,而 Java 在 JVM 上運行。語法:Node.js 使用 JavaScript 語法,而 Java 使用 Java 語法。用途:Node.js 適用於 I/O 密集型任務,而 Java 適用於大型企業應用程式。

See all articles