Linux Bash スクリプトのバグやタイプミスは、スクリプトの実行時に悲惨な結果をもたらす可能性があります。スクリプトを実行する前に構文をチェックする方法をいくつか紹介します。
厄介なバグたち
コードを書くのは難しいです。より正確に言えば、バグのない重要なコードを書くのは困難です。また、プログラムまたはスクリプト内のコード行が増えるほど、 バグ が存在する可能性が高くなります。
プログラミングに使用する言語はこれに直接関係します。アセンブリでのプログラミングは C でのプログラミングよりもはるかに難しく、C でのプログラミングは Python でのプログラミングよりも困難です。プログラミングしている言語が低レベルであればあるほど、自分で行う必要がある作業が多くなります。 Python は組み込みのガベージ コレクション ルーチンを利用できるかもしれませんが、C とアセンブリは確実に利用できません。
Linux シェル スクリプトの作成には、 それ自体に課題が伴います。 C などのコンパイル済み言語では、コンパイラと呼ばれるプログラムがソース コード (テキスト ファイルに入力した人間が判読可能な命令) を読み取り、それをバイナリの実行可能ファイルに変換します。 バイナリ ファイルには、コンピュータが理解して動作できるマシン コード命令が含まれています。
コンパイラは、読み取って解析しているソース コードが言語の構文やその他の規則に従っている場合にのみバイナリ ファイルを生成します。予約語 (言語のコマンド語の 1 つ) または変数名の綴りを間違えると、コンパイラはエラーをスローします。
たとえば、変数を使用する前に 変数 を宣言する必要がある言語もあれば、そこまで手間のかからない言語もあります。使用している言語で変数を宣言する必要があるのにそれを忘れた場合、コンパイラは別のエラー メッセージをスローします。これらのコンパイル時エラーは煩わしいものですが、多くの問題を検出し、対処する必要があります。しかし、たとえ構文上のバグがないプログラムであっても、プログラムにバグがないわけではありません。それとは程遠い。
論理的な欠陥が原因のバグは、通常、発見するのがはるかに困難です。プログラムに 2 と 3 を足すように指示しても、実際には 2 と 2 を足すことを望んでいた場合、期待した答えは得られません。しかし、プログラムは、書かれたとおりのことを実行しています。プログラムの構成や構文に問題はありません。問題はあなたです。意図したとおりに動作しない、整形式のプログラムを作成しました。
テストは難しい
プログラムを徹底的にテストするには、たとえ単純なプログラムであっても時間がかかります。数回実行するだけでは十分ではありません。実際には、コード内のすべての実行パスをテストして、コードのすべての部分が検証されるようにする必要があります。プログラムが入力を要求する場合、受け入れられない入力を含むすべての条件をテストするのに十分な範囲の入力値を提供する必要があります。
高水準言語の場合、単体テストと自動テストは、徹底的なテストを管理しやすいものにするのに役立ちます。そこで質問は、バグのない Bash シェル スクリプトを作成するのに役立つツールはあるのか、ということです。
Bash シェル自体も含めて、答えは「はい」です。
Bash を使用してスクリプト構文をチェックする
Bash
-n
(noexec) オプションは、スクリプトを実行せずに、スクリプトを読み取って構文エラーをチェックするように Bash に指示します。スクリプトの目的によっては、スクリプトを実行して問題を探すよりもはるかに安全な場合があります。
確認するスクリプトは次のとおりです。これは複雑ではなく、主に
if
ステートメント
のセットです。月を表す数値の入力を求められ、それが受け入れられます。スクリプトによって、その月がどの季節に属するかが決まります。明らかに、ユーザーがまったく入力を提供しないか、数字の代わりに文字などの無効な入力を提供した場合、これは機能しません。
#! /bin/bash
read -p “月を入力してください (1 ~ 12): ” month
# 何か入力しましたか?
if [ -z “$month” ]
それから
echo “月を表す数値を入力する必要があります。”
出口1
フィ
# 有効な月ですか?
if (( “$month” < 1 || “$month” > 12));それから
echo “月は 1 から 12 までの数字でなければなりません。”
0番出口
フィ
#春ですか?
if (( “$month” >= 3 && “$month” < 6));それから
エコー「それは春の月ですね。」
0番出口
フィ
#今日は夏ですか?
if (( “$month” >= 6 && “$month” < 9));それから
エコー「それは夏の月ですね。」
0番出口
フィ
#秋ですか?
if (( “$month” >= 9 && “$month” < 12));それから
echo 「それは秋の月です。」
0番出口
フィ
# きっと冬の月でしょう
エコー「それは冬の月ですね。」
0番出口
このセクションでは、ユーザーが何かを入力したかどうかを確認します。
$month
変数が設定されていないかどうかをテストします。
if [ -z "$month" ]
それから
echo “月を表す数値を入力する必要があります。”
出口1
フィ
このセクションでは、1 ~ 12 の数値が入力されたかどうかがチェックされます。また、文字や句読点記号は数値に変換されないため、数字ではない無効な入力もトラップされます。
# 有効な月ですか?
if (( “$month” < 1 || “$month” > 12));それから
echo “月は 1 から 12 までの数字でなければなりません。”
0番出口
フィ
他のすべての If 句は、
$month
変数の値が 2 つの値の間にあるかどうかをチェックします。そうであれば、その月はその季節に属します。たとえば、ユーザーが入力した月が 6、7、または 8 の場合、それは夏の月です。
#今日は夏ですか?
if (( “$month” >= 6 && “$month” < 9));それから
エコー「それは夏の月ですね。」
0番出口
フィ
この例を実行したい場合は、スクリプトのテキストをコピーしてエディターに貼り付け、「seasons.sh」という名前で保存します。次に、
chmod
コマンド
を使用してスクリプトを実行可能にします。
chmod +x シーズン.sh
スクリプトをテストするには、
- まったく入力を提供しません。
- 数値以外の入力を提供します。
- 1 ~ 12 の範囲外の数値を指定します。
- 1 ~ 12 の範囲の数値を指定します。
いずれの場合も、同じコマンドでスクリプトを開始します。唯一の違いは、スクリプトによってプロモートされるときにユーザーが提供する入力です。
./seasons.sh
それは期待どおりに機能するようです。
Bash
にスクリプトの構文をチェックしてもらいましょう。これを行うには、
-n
(noexec) オプションを呼び出し、スクリプトの名前を渡します。
bash -n ./seasons.sh
これは「ニュースがないことは良いニュースである」というケースです。何も言わずにコマンド プロンプトに戻すのは、Bash がすべて問題ないようであることを示す方法です。スクリプトを妨害してエラーを導入してみましょう。
最初の
if
節から
then
を削除します。
# 有効な月ですか?
if (( “$month” < 1 || “$month” > 12)); # 「その後」が削除されました
echo “月は 1 から 12 までの数字でなければなりません。”
0番出口
フィ
次に、最初はユーザー入力なしで、次にユーザーからの入力ありでスクリプトを実行してみましょう。
./seasons.sh
スクリプトが初めて実行されるとき、ユーザーは値を入力しないため、スクリプトは終了します。私たちが妨害したセクションには決して到達しません。スクリプトは、Bash からのエラー メッセージを表示せずに終了します。
スクリプトが 2 回目に実行されるとき、ユーザーは入力値を指定し、最初の if 句が実行されてユーザーの入力の健全性がチェックされます。これにより、Bash からのエラー メッセージが表示されます。
Bash はスクリプトのロジックを気にしないため、その句の構文とコードの 1 行おきの構文をチェックすることに注意してください。スクリプトは実行されていないため、Bash がスクリプトをチェックするときに、ユーザーは数値の入力を求められません。
スクリプトのさまざまな実行パスは、Bash が構文をチェックする方法には影響しません。 Bash は、スクリプトの先頭から最後までシンプルかつ系統的に動作し、各行の構文をチェックします。
ShellCheck ユーティリティ
リンター — Unix 全盛期の C ソース コード チェック ツールにちなんで名付けられた — は、プログラミング エラー、スタイル エラー、言語の疑わしい使用法または疑わしい使用法を検出するために使用されるコード分析ツールです。リンターは多くのプログラミング言語で利用でき、衒学的であることで有名です。リンターが見つけたものすべてがそれ自体バグであるわけではありませんが、リンターによって気づかれるものはすべて注目に値するでしょう。
ShellCheck は 、シェル スクリプトのコード分析ツールです。これは Bash のリンターのように動作します。
不足してい
then
予約語をスクリプトに戻して、別のことを試してみましょう。最初の
if
句から左括弧「[」を削除します。
# 何か入力しましたか?
if -z “$month” ] # 左括弧 “[” が削除されました
それから
echo “月を表す数値を入力する必要があります。”
出口1
フィ
Bash を使用してスクリプトをチェックすると、問題は見つかりませんでした。
bash -n 季節.sh
./seasons.sh
しかし、スクリプトを実行しようとすると、エラー メッセージが表示されます。また、エラー メッセージが表示されても、スクリプトは実行を続けます。これが、一部のバグが非常に危険である理由です。スクリプト内でその後実行されるアクションがユーザーからの有効な入力に依存している場合、スクリプトの動作は予測不能になります。データを危険にさらす可能性があります。
Bash
-n
(noexec) オプションがスクリプト内のエラーを見つけられない理由は、左括弧「[」が
[
と呼ばれる外部プログラムであるためです。これは Bash の一部ではありません。これは
、
test
コマンドを使用する簡単な方法
です。
Bash は、スクリプトの検証時に外部プログラムの使用をチェックしません。
ShellCheck のインストール
ShellCheck にはインストールが必要です。 Ubuntu にインストールするには、次のように入力します。
sudo apt install シェルチェック
Fedora に ShellCheck をインストールするには、次のコマンドを使用します。パッケージ名は大文字と小文字が混在していますが、ターミナル ウィンドウでコマンドを発行するとすべて小文字になることに注意してください。
sudo dnf インストール ShellCheck
Manjaro および類似の
Arch
ベースのディストリビューションでは、
pacman
使用します。
sudo pacman -S シェルチェック
シェルチェックの使用
スクリプトで ShellCheck を実行してみましょう。
シェルチェックシーズン.sh
ShellCheck は問題を見つけて私たちに報告し、詳細情報へのリンクのセットを提供します。リンクを 右クリックし 、表示されるコンテキスト メニューから [リンクを開く] を選択すると、リンクがブラウザで開きます。
ShellCheck は、それほど深刻ではない別の問題も発見しました。緑色の文字で報告されます。これは、完全なエラーではなく、警告であることを示しています。
エラーを修正し、欠落している「[.」を置き換えてみましょう。バグ修正戦略の 1 つは、優先度の最も高い問題を最初に修正し、後で警告などの優先度の低い問題に取り組むことです。
欠落している「[」を置き換えて、ShellCheck をもう一度実行しました。
シェルチェックシーズン.sh
ShellCheck からの唯一の出力は以前の警告を参照しているため、これは問題ありません。修正が必要な優先度の高い問題はありません。
この警告は、
-r
(そのまま読み取り) オプションを指定せずに
read
コマンドを使用すると、入力内のバックスラッシュがエスケープ文字として扱われることを示しています。これは、リンターが生成できる種類の衒学的出力の良い例です。この場合、ユーザーはバックスラッシュを入力すべきではありません。数値を入力する必要があります。
このような警告には、プログラマ側の判断が必要です。直す努力をしますか、それともそのままにしておきますか? 2 秒で簡単に修正できます。また、ShellCheck の出力に警告が表示されることもなくなるので、そのアドバイスを受け入れたほうがよいでしょう。 「r」を追加して
read
コマンドのフラグをオプションにし、スクリプトを保存します。
read -pr "月を入力してください (1 ~ 12): " month
ShellCheck をもう一度実行すると、クリーンな健康状態がわかります。
ShellCheck はあなたの友達です
ShellCheck は 、あらゆる範囲の問題 を検出、報告、アドバイスできます。 不良コードのギャラリー をチェックしてください。これにより、検出できる問題の種類がわかります。
これは無料で高速で、シェル スクリプトを作成する手間が大幅に軽減されます。何が気に入らないのか?





