ホームページ  >  記事  >  ウェブフロントエンド  >  Nodejs が bash スクリプトを実行するためのいくつかのオプションに関する簡単な説明

Nodejs が bash スクリプトを実行するためのいくつかのオプションに関する簡単な説明

青灯夜游
青灯夜游転載
2021-07-08 11:12:023320ブラウズ

nodejsbash スクリプトを実行するにはどうすればよいですか?この記事では、ノードが 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: パラメータが設定されていません」というプロンプトが表示されます。

もう一度想像してください。最初に削除しようとしていたのは次のとおりです:rm -rf $dir /*では、dir が空の場合はどうなるでしょうか? rm -rf は削除コマンドです。$dir が空の場合、すべてのファイルとファイルを削除する rm -rf /* を実行するのと同じです。フォルダー。 。 。そうするとシステムが消えてしまいます これが伝説のデータベース削除逃走か~~~~~~~~~

nodeやブラウザ環境であれば直接varを実行します= == 'abc' は間違いなくエラーを報告します。つまり、JavaScript プログラミングの多くの経験は bash では再利用できません。再利用できれば素晴らしいと思います。

その後、bash の代わりに node スクリプトが使用されたらどれほど素晴らしいだろうかと模索し始めました。1 日試した後、徐々に成果物を発見しました。 Google が所有する zx ライブラリです。心配しないでください。このライブラリを最初に紹介するつもりはありません。まず、現在の主流の node がどのように使用されているかを見てみましょう。 bash スクリプトを作成すれば、その理由がわかるでしょう。

ノードは bash スクリプトを実行します: 消極的な解決策: child_process API

たとえば、child_process# の API の execcommand# #

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 モジュールがコマンドを実行できない場合、このオブジェクトは null ではありません。たとえば、ファイルを検索してもファイルが見つからない場合、エラー オブジェクトは空ではありません。ただし、コマンドが正常に実行され、メッセージが標準エラー ストリームに書き込まれる場合、stderr オブジェクトは空にはなりません。

もちろん、同期

exec コマンド execSync

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

// 同步创建了一个hello的文件夹
execSync("mkdir hello");

を使用できます。 bash コマンドを実行できる child_process の他の 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);
}
(From)上記のコードを見ると、shelljs は、nodejs で bash スクリプトを記述するための非常に優れたソリューションです。ノード環境を自由にアップグレードできない場合は、shelljs で十分だと思います。

それでは今日の主役zxを見ていきましょう、スタートはすでに17.4kです。

zx library

公式サイト: 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 ファイルは、ノードの上位バージョンに付属し、es6 モジュールをサポートするファイルの最後です。つまり、このファイルは、他のツールでエスケープせずにモジュールを実行可能

2. パイプライン操作のパイプ メソッドのサポートが付属しています

3. ネットワーク リクエストを作成できるフェッチ ライブラリが付属しています。印刷できるチョーク ライブラリが付属しています。カラーフォント。エラー処理の 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 'zx'await $`date`复制代码

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

zx examples/typescript.ts

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

以上がNodejs が bash スクリプトを実行するためのいくつかのオプションに関する簡単な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。