Bash スクリプトの入門

スクリプトは、一連のコマンドを含むテキスト ファイルです。シェルはこのファイルを読み取り、コマンド ラインに直接入力されたかのように、ファイル内のすべてのコマンドを順番に実行します。コマンドラインで実行できるタスクはすべて、スクリプトを使用して実行できます。

スクリプトの利点は、スクリプトを再利用したり、システムの起動時やシャットダウン時にスクリプトを自動的に実行するなど、特定の機会に自動的に呼び出されるように指定できることです。

シバン OK

スクリプトの最初の行は通常、スクリプトを実行する必要があるインタープリタを指定します。この行はシバンと呼ばれる「#!」文字で始まるため、この行はシバン行と呼ばれます。

#! に続くのは、スクリプト インタープリターの場所です。Bash スクリプトのインタープリターは通常、/bin/sh または /bin/bash です。

#!/bin/sh
# または
#!/bin/bash

#! とスクリプト インタプリタの間にはスペースはありません。

Bash インタプリタがディレクトリ /bin に配置されていない場合、スクリプトは実行できません。念のため、次のように書くこともできます。

#!/usr/bin/env bash

上記のコマンドは、env コマンド (このコマンドは常に /usr/bin ディレクトリにあります) を使用して、Bash 実行可能ファイルの場所を返します。 「env」コマンドの詳細については、次の記事を参照してください。

Shebang 行は必須ではありませんが、推奨されます。この行が欠落している場合は、スクリプトを手動でインタープリタに渡す必要があります。例えばスクリプトが「script.sh」の場合、Shebang行があれば直接呼び出して実行することができます。

$ ./script.sh

上記の例では、script.sh がスクリプト ファイル名です。通常、スクリプトには「.sh」接尾辞が付いていますが、これは必須ではありません。

Shebang 行がないと、実行のためにスクリプトをインタプリタに手動で渡すことしかできません。

$ /bin/sh ./script.sh
# または
$ bash ./script.sh

実行権限とパス

前述したように、シバン行スクリプトを指定すれば、直接実行することができます。これには前提条件があります。つまり、スクリプトには実行権限が必要です。次のコマンドを使用して、スクリプトに実行権限を付与できます。

#すべてのユーザーに実行権限を与える
$ chmod +x スクリプト.sh

#すべてのユーザーに読み取りと実行の権限を与える
$ chmod +rx スクリプト.sh
# または
$ chmod 755 スクリプト.sh

# スクリプト所有者にのみ読み取りおよび実行権限を与える
$ chmod u+rx スクリプト.sh

スクリプトのアクセス許可は通常、「755」 (所有者はすべてのアクセス許可を持ち、その他のユーザーは読み取りおよび実行のアクセス許可を持ちます) または「700」 (所有者のみが実行可能) に設定されます。

スクリプトを呼び出すときは、実行権限に加えて、通常、スクリプトのパス (path/script.sh など) を指定する必要があります。環境変数 $PATH で指定したディレクトリにスクリプトを配置する場合は、パスを指定する必要はありません。 Bash は自動的にこれらのディレクトリに移動して、同じ名前の実行可能ファイルがあるかどうかを確認するためです。

実行可能スクリプトを特別に保存するために、メイン ディレクトリに新しい ~/bin サブディレクトリを作成し、~/bin$PATH に追加することをお勧めします。

エクスポート PATH=$PATH:~/bin

上記のコマンドは、環境変数 $PATH を変更し、$PATH の末尾に ~/bin を追加します。この行を ~/.bashrc ファイルに追加し、.bashrc を 1 回リロードすると、この設定が有効になります。

$ ソース ~/.bashrc

今後は、どのディレクトリにあっても、スクリプトファイル名を直接入力するだけでスクリプトが実行されます。

$スクリプト.sh

script.sh$PATHで指定されたディレクトリにあるため、上記のコマンドではスクリプトのパスを指定していません。

env コマンド

env コマンドは常に /usr/bin/env ファイルを指します。つまり、このバイナリ ファイルは常に /usr/bin ディレクトリにあります。

構文 #!/usr/bin/env NAME は、シェルに最初に一致する NAME$PATH 環境変数内で検索させることを意味します。これは、コマンドの特定のパスがわからない場合、または他のユーザーのマシンと互換性を持たせたい場合に便利です。

/usr/bin/env bash は、bash のパスが $PATH にある場合に、bash 実行可能ファイルの場所を返すことを意味します。他のスクリプト ファイルでもこの​​コマンドを使用できます。たとえば、Node.js スクリプトの Shebang 行は次のように記述できます。

#!/usr/bin/env ノード

envコマンドのパラメータは以下の通りです。

  • -i--ignore-environment: 環境変数なしで開始します。
  • -u--unset=NAME: 環境変数から変数を削除します。
  • --help: ヘルプを表示します。
  • --version: バージョン情報を出力します。

以下は、環境変数を使用せずに新しいシェルを作成する例です。

$ env -i /bin/sh

コメント

Bash スクリプトでは、「#」はコメントを表し、行の先頭または末尾に配置できます。

# この行はコメントです
「Hello World!」をエコーする

echo 'Hello World!' # # の後の部分もコメントです

スクリプトの先頭にコメントを使用して現在のスクリプトの機能を説明することをお勧めします。これにより、将来のメンテナンスが容易になります。

スクリプトパラメータ

スクリプトを呼び出す場合、スクリプト ファイル名の後にパラメータを続けることができます。

$ script.sh word1 word2 word3

上記の例では、script.sh がスクリプト ファイルで、word1word2word3 が 3 つのパラメータです。

スクリプト ファイル内で、特別な変数を使用してこれらのパラメータを参照できます。

  • $0: スクリプト ファイル名、つまり script.sh
  • $1~$9: スクリプトの第1パラメータから第9パラメータに対応します。
  • $#: パラメータの総数。
  • $@: スペースで区切られたすべてのパラメータ。
  • $*: すべてのパラメータ。パラメータは変数 $IFS 値の最初の文字で区切られます。デフォルトはスペースですが、カスタマイズできます。

スクリプトに 9 個を超えるパラメータがある場合は、10 番目のパラメータを ${10} などの形式で引用できます。

コマンドが「command -o foo bar」の場合、「-o」は「$1」、「foo」は「$2」、「bar」は「$3」になることに注意してください。

以下は、スクリプト内のコマンド ライン パラメーターを読み取る例です。

#!/bin/bash
#script.sh

echo "すべてのパラメータ:" $@
echo "コマンドラインパラメータの数:" $#
エコー '$0 = ' $0
エコー '$1 = ' $1
エコー '$2 = ' $2
エコー '$3 = ' $3

実行結果は以下の通りです。

$ ./script.sh a b c
すべてのパラメータ: a b c
コマンドラインパラメータの数: 3
$0 = スクリプト.sh
1 ドル =
$2 = b
$3 = c

ユーザーは任意の数のパラメータを入力でき、各パラメータは「for」ループを使用して読み取ることができます。

#!/bin/bash

私は「$@」で行います。
  エコー $i
終わり

上の例では、$@ はすべてのパラメータのリストを返し、for を使用してそれらをループします。

複数のパラメータを二重引用符で囲んだ場合、それらは 1 つのパラメータとして扱われます。

$ ./script.sh "a b"

上の例では、Bash は "a b" をパラメータとみなして、$1a b を返します。返すときは二重引用符が含まれないことに注意してください。

シフトコマンド

shift コマンドは、実行されるたびに、スクリプトの現在の最初のパラメータ ($1) を削除し、後続のパラメータを 1 桁進めます。つまり、$2$1' になります。 , $3$2 になり、$4$3 になります。

「while」ループと「shift」コマンドを組み合わせて各パラメータを読み取ることもできます。

#!/bin/bash

echo "合計 $# 個のパラメータが入力されました"

while [ "$1" != "" ];
  echo "$# パラメータが残っています"
  echo "パラメータ: $1"
  シフト
終わり

上の例では、「shift」コマンドは毎回現在の最初のパラメータを削除し、それによって「while」ループを通じてすべてのパラメータを走査します。

shift コマンドはパラメータとして整数を受け取ることができ、削除するパラメータの数を指定します。デフォルトは 1 です。

シフト3

上記のコマンドは最初の 3 つのパラメータを削除し、元の $4$1 になります。

getopts コマンド

getopts コマンドは、複雑なスクリプト コマンド ライン パラメータを解析するためにスクリプト内で使用され、通常は、先行接続行 (-) が付いたスクリプトのすべてのパラメータを削除するために while ループとともに使用されます。

getopts オプト文字列名

2 つのパラメータを取ります。最初のパラメータ optstring は、スクリプトのすべての接続線パラメータを指定する文字列です。たとえば、スクリプトには 3 つの構成項目パラメータ -l-h、および -a を含めることができます。パラメータ値を持つことができるのは -a だけであり、-l-h はスイッチです。パラメータの場合、getopts の最初のパラメータは lha: として記述されます。順序は重要ではありません。 「a」の後にコロンがあることに注意してください。これは、パラメータにパラメータ値があることを示しており、「getopts」はパラメータ値を持つ構成項目パラメータを指定し、その後にコロン (「:」) を続ける必要があります。 getopts の 2 番目のパラメータ name は変数名で、現在取得されている設定項目パラメータ、つまり lh、または a を保存するために使用されます。

以下に例を示します。

while getopts 'lha:' オプション;
  「$OPTION」の場合
    l)
      「linuxconfig」をエコーする
      ;;

    h)
      エコー「hはhの略です」
      ;;

    a)
      avalue="$OPTARG"
      echo "指定された値は $OPTARG です"
      ;;
    ?)
      echo "スクリプトの使用法: $(basename $0) [-l] [-h] [-a somevalue]" >&2
      出口1
      ;;
  イーサック
終わり
シフト "$(($OPTIND - 1))"

上記の例では、「while」ループは「getopts 'lha:' OPTION」コマンドを継続的に実行し、各実行で接続線パラメータ (および対応するパラメータ値) を読み取り、ループ本体に入ります。変数 OPTION は、現在処理中の結合線パラメータ (すなわち、lh、または a) を保存します。ユーザーが指定されていないパラメータ (-x など) を入力した場合、OPTION? と等しくなります。ループ本体は「case」判断を使用して、これら 4 つの異なる状況を処理します。

結合線パラメータに「-a foo」などのパラメータ値がある場合、「a」パラメータを処理するときに、環境変数「$OPTARG」にパラメータ値が保存されます。

結合線のないパラメータに遭遇すると、getopts は実行に失敗し、while ループを終了することに注意してください。たとえば、getoptscommand -l foo を解析できますが、command foo -l は解析できません。また、command -lhgetopts などの形式でまとめて記述された複数の接続線パラメータも正しく処理できます。

変数 $OPTIND は、getopts が実行を開始する前は 1 であり、その後、実行されるたびに 1 ずつ増加します。 「while」ループが終了すると、すべての接続線パラメータが処理されたことを意味します。この時点で、$OPTIND - 1 は、処理された結合線パラメータの数です。これを後続のコードで確実に使用できるように、shift コマンドを使用してこれらのパラメータを削除します。コマンドの主要パラメータを処理します。

設定項目パラメータターミネータ --

「-」と「--」で始まるパラメータは、Bash によって設定項目として解釈されます。ただし、それらは設定項目ではなく、「-f」または「--file」と呼ばれるファイル名などのエンティティ パラメータの一部である場合もあります。

$ 猫 -f
$ cat --ファイル

上記のコマンドの本来の目的は、ファイル -f および --file の内容を出力することですが、これは Bash によって設定項目として解釈されます。

このとき、設定項目パラメータ ターミネータ -- を使用できます。その機能は、その背後にあるパラメータの先頭にある --- が設定項目ではなく、解釈のみが可能であることを Bash に伝えることです。エンティティパラメータとして。

$ cat -- -f
$ cat -- --file

上記のコマンドは、ファイル -f--file の内容を正しく表示できます。これは、これらのファイルが -- の後に配置され、先頭の --- が次のように解釈されなくなるためです。設定項目。

変数が設定項目として解釈されないようにする場合は、変数の前にパラメータ ターミネータ -- を置きます。

$ls -- $myPath

上記の例では、-- は変数 $myPath をエンティティ パラメーター (つまり、パス名) としてのみ解釈するように強制します。変数がパス名ではない場合、エラーが報告されます。

$ myPath="-l"
$ls -- $myPath
ls: '-l' にアクセスできません: そのようなファイルまたはディレクトリはありません

上の例では、変数 myPath の値はパスではなく -l です。ただし、「--」を指定すると、「$myPath」がパスとしてのみ解釈されるため、「パスが存在しません」というエラーが発生します。

ファイル内で --hello を検索する場合は、パラメータ ターミネータ -- も使用する必要があります。

$ grep -- "--hello" example.txt

上記のコマンドは、example.txt ファイル内で文字列 --hello を検索します。この文字列は -- で始まります。パラメータ ターミネータが使用されていない場合、grep コマンドは --hello を設定パラメータとして扱い、エラーを報告します。

終了コマンド

「exit」コマンドは、現在のスクリプトの実行を終了し、シェルに終了値を返すために使用されます。

$exit

上記のコマンドは現在のスクリプトを終了し、最後のコマンドの終了ステータスをスクリプト全体の終了ステータスとして使用します。

「exit」コマンドの後には、終了ステータスであるパラメータを続けることができます。

#終了値は 0 (成功)
$出口0

#終了値は 1 (失敗)
$出口1

終了時に、スクリプトは終了値を返します。スクリプトの終了値。「0」は正常を意味し、「1」はエラーが発生したことを意味し、「2」は不正な使用法を意味し、「126」は実行可能なスクリプトではないことを意味し、「127」はコマンドが見つからなかったことを意味します。スクリプトがシグナル「N」によって終了した場合、終了値は「128 + N」になります。簡単に言えば、終了値がゼロ以外である限り、実行エラーとみなされます。

以下に例を示します。

if [ $(id -u) != "0" ];
  echo "現在のスクリプトを実行できるのは root ユーザーだけです"
  出口1
フィ

上の例では、id -u コマンドはユーザーの ID を返します。ユーザーの ID が 0 (root ユーザーの ID) に等しくない場合、スクリプトは終了コード 1 で終了します。操作が失敗したことを示します。

「exit」コマンドと「return」コマンドの違いは、「return」コマンドは関数を終了して呼び出し元に値を返し、スクリプトは引き続き実行されることです。 exit はスクリプト全体の終了です。関数内で exit を呼び出すと、関数を終了してスクリプトの実行を終了します。

コマンド実行結果

コマンドの実行が完了すると戻り値が返されます。 「0」は実行が成功したことを示し、「0」以外(通常は「1」)は実行が失敗したことを示します。環境変数 $? は前のコマンドの戻り値を読み取ることができます。

これを利用することで、スクリプト内でコマンドの実行結果を判定することができます。

cd /パス/への/どこか
if [ "$?" = "0" ];
  rm*
それ以外
  echo "ディレクトリを切り替えられません!"
  出口1
フィ

上記の例では、コマンド cd /path/to/somewhere が正常に実行された場合 (戻り値が 0 に等しい)、ディレクトリ内のファイルが削除されます。それ以外の場合、スクリプトは終了してリターンされます。スクリプト全体の値が「1」になると実行失敗を示します。

if はコマンドの実行結果を直接判定して対応する動作を行うことができるため、上記のスクリプトは次のように書き換えることができます。

cd /path/to/somewhere の場合;
  rm*
それ以外
  echo "ディレクトリを変更できませんでした! 1>&2 を中止します。"
  出口1
フィ

より簡潔な記述方法は、2 つの論理演算子 && (and) と || (or) を使用することです。

# 2 番目のステップは、最初のステップが正常に実行された後にのみ実行されます。
cd /path/to/somewhere && rm *

# 最初のステップが失敗した場合、2 番目のステップが実行されます。
cd /path/to/somewhere 出口 1 ||

ソースコマンド

「source」コマンドはスクリプトを実行するために使用され、通常は設定ファイルをリロードするために使用されます。

$ ソース .bashrc

「source」コマンドの最大の特徴は、スクリプトを直接実行する場合と異なり、新しいサブシェルが作成され、現在のシェル内でスクリプトを実行することです。したがって、「source」コマンドがスクリプトを実行する場合、「export」変数は必要ありません。

#!/bin/bash
#test.sh
エコー $foo

上記のスクリプトは、$foo 変数の値を出力します。

#現在のシェルに新しい変数 foo を作成します
$foo=1

# プリントアウト 1
$ソーステスト.sh
1

#空の文字列を出力する
$ bash テスト.sh

上記の例では、現在のシェル変数 foo には export がないため、直接実行では読み込むことができませんが、source 実行では読み込むことができます。

「source」コマンドのもう 1 つの用途は、スクリプト内で外部ライブラリをロードすることです。

#!/bin/bash

ソース ./lib.sh

function_from_lib

上記のスクリプトは、内部で「source」コマンドを使用して外部ライブラリをロードし、この外部ライブラリによって定義された関数をスクリプト内で使用できるようになります。

「source」にはドット (「.」) で表すことができる短縮形があります。

$ ..bashrc

エイリアス、エイリアスコマンド

alias コマンドは、コマンドのエイリアスを指定するために使用されます。これにより、覚えやすくなります。 aliasのフォーマットは以下の通りです。

エイリアス NAME=DEFINITION

上記のコマンドにおいて、NAME はエイリアスの名前、DEFINITION はエイリアスに対応する元のコマンドです。等号の両側にスペースを入れることはできません。スペースを入れないとエラーが報告されます。

一般的な例は、grep コマンドに search のエイリアスを与えることです。

エイリアス検索=grep

alias は、長いコマンドに対して短いエイリアスを指定するためにも使用できます。以下は、エイリアスを介して「today」を定義するコマンドです。

$ alias today='date +"%A, %B %-d, %Y"'
今日の$
2020年1月6日月曜日

ファイルを誤って削除することを防ぐために、「rm」コマンドのエイリアスを指定できる場合があります。

$ エイリアス rm='rm -i'

上記のコマンドは、「rm」コマンドが「rm -i」であることを指定しており、ユーザーはファイルを削除する前に毎回確認を求められます。

「alias」で定義したエイリアスもパラメータを受け入れることができ、パラメータは元のコマンドに直接渡されます。

$ alias echo='echo それは言う: '
$ エコーハローワールド
それは言う: こんにちは、世界

上の例では、エイリアスは echo コマンドの最初の 2 つのパラメータを定義します。これは、echo コマンドのデフォルトの動作を変更するのと同じです。

エイリアスを指定した後は、他のコマンドと同様に使用できます。一般的によく使われるエイリアスは ~/.bashrc の最後に記述します。また、エイリアスはコマンドに対してのみ定義できます。それ以外の部分(非常に長いパスなど)に対してエイリアスを定義することは無効です。

すべてのエイリアスを表示するには、「alias」コマンドを直接呼び出します。

$エイリアス

unalias コマンドはエイリアスを元に戻すことができます。

$unaliaslt

参考リンク


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0