デバッグは、プログラムのエラーを修正するのに役立ちます。この記事では、LinuxおよびUnixオペレーティングシステムでbashスクリプトをデバッグするためのさまざまな方法について説明します。
はじめに
プログラミングの最初の頃は、コード内のエラーを見つけるために何時間も費やしてきましたが、結局、それは単純なことかもしれません。あなたも同じ状況に直面したかもしれません。
適切なデバッグ手法の使用方法を知っていると、エラーをすばやく解決するのに役立ちます。 PythonやJavaなどの他の言語とは異なり、ブレークポイントを設定したり、コードをステップオーバーしたりできるbash用のデバッガーツールはありません。
bashシェルスクリプトのデバッグに役立つ組み込み機能がいくつかあります。これらの機能については、次のセクションで詳しく説明します。
デバッグオプションを使用する3つの方法
スクリプトでデバッグオプションを有効にする場合は、3つの方法で有効にできます。
1 。スクリプトを呼び出すときに、ターミナルシェルからデバッグオプションを有効にします。
$ bash [ debugging flags ] scriptname
2 。スクリプトのshebang行にデバッグフラグを渡して、デバッグオプションを有効にします。
#!/bin/bash [ debugging flags ]
3 。 set
を使用して、デバッグオプションを有効にします スクリプトからのコマンド。
set -o nounset
set -u
Setコマンドは何に使用されますか?
set
commandは、bashパラメーターを制御し、特定の方法でbashの動作を変更するために使用できるシェル組み込みコマンドです。
通常、シェルの動作を変更するためにターミナルからsetコマンドを実行することはありません。これは、デバッグまたはbashstrictモードを有効にするためにシェルスクリプト内で広く使用されます。
$ type -a set
set is a shell builtin
setコマンドのヘルプセクションにアクセスして、サポートされているフラグと各フラグの機能を確認できます。
$ set --help
スクリプトの一部または完全なスクリプトをデバッグする
デバッグオプションについて学習する前に、スクリプト全体またはコードの特定の部分のみをデバッグできることを理解する必要があります。デバッグオプションを有効または無効にするには、setコマンドを使用する必要があります。
-
set -<debugging-flag>
デバッグモードを有効にします。 -
set +<debugging-flag>
デバッグモードを無効にします。
以下のコードを見てください。 set -x
スクリプトのxtraceモードを有効にし、set +x
xtraceモードを無効にします。 set -x
の間にあるもの およびset +x
xtraceデバッグモードで実行されます。
次のセクションでxtraceモードについて学習します。したがって、デバッグフラグの場合、覚えておく必要があるのは、 set -
だけです。 モードを有効にし、 set +
モードを無効にします。
#!/bin/bash set -x read -p "Pass Dir name : " D_OBJECT read -p "Pass File name : " F_OBJECT set +x touch ${D_OBJECT}/${F_OBJECT}
変数が定義されていない場合は失敗します
bashの変数を操作する場合 、欠点は、未定義の変数を使用しようとしても、「変数が定義されていません」などのエラーメッセージが表示されてスクリプトが失敗しないことです。 。代わりに、空の文字列を出力します。
ユーザーから入力を取得し、それを変数$OBJECT
に格納している以下のコードを見てください。 。テスト演算子を実行しようとしました(-f
および-d
)$OBJECT1
で 定義されていない変数。
#!/bin/bash read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT1 ]] then echo "$OBJECT is a directory" fiです
このコードを実行すると、エラーがスローされるはずでしたが、エラーは発生せず、スクリプトでさえリターンコードゼロで終了しました。

この動作をオーバーライドするには、-u
を使用します 未定義の変数が使用されたときにエラーをスローするフラグ。
間違った変数名で同じコードを再度実行しますが、今回は「バインドされていない変数」をスローします エラー。

-u
を設定することもできます set
を使用するオプション コマンドを実行するか、それを引数としてshebangに渡します。
set -u
set -o nounset
(または)
#! /bin/bash -u
救助のためのXtraceモード
これは、論理エラーのbashスクリプトをデバッグするときに広く使用するモードです。 Xtrace modeは、コードを1行ずつ表示しますが、パラメーターは展開されます。
前のセクションで、-u
なしでコードを実行したとき フラグ、正常に完了しましたが、ターミナルでの出力を期待していました。これで、同じスクリプトをxtraceモードで実行して、スクリプトのどこで問題が発生しているかを正確に確認できます。
次のサンプルコードをご覧ください。
#!/bin/bash read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT1 ]] then echo "$OBJECT is a directory" fiです
上記のコードを実行すると、出力が返されません。

この問題をデバッグするために、 xtraceでスクリプトを実行できます。 -x
を渡すことによるモード 国旗。
以下の出力では、変数が展開されて出力されていることがわかります。これは、条件ステートメント-f
に割り当てられた空の文字列があることを示しています。 および-d
。このようにして、エラーを論理的にチェックして修正できます。

出力に表示されるプラス記号は、PS4
を設定することで変更できます。 スクリプト内の変数。デフォルトでは、PS4は(+
に設定されています 。
$ echo $PS4
+
$ PS4=" ==> " bash -x debugging.sh

setコマンドを使用してXtraceモードを設定するか、引数としてshebangに渡すこともできます。
set -x
set -o xtrace
(または)
#! /bin/bash -x
同様に、デバッグ時に、Xtraceデバッグログをターミナルに出力する代わりにファイルにリダイレクトできます。
以下のコードを見てください。 .log
にファイル記述子6を割り当てています ファイルとBASH_XTRACEFD="6"
xtraceデバッグログをファイル記述子6にリダイレクトします。
#!/bin/bash exec 6> redirected_debug.log PS4=' ==> ' BASH_XTRACEFD="6" read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT1 ]] then echo "$OBJECT is a directory" fi
ターミナルでxtrace出力を出力する代わりにこのコードを実行すると、.log
にリダイレクトされます。 ファイル。
$ cat redirected_debug.log ==> read -p 'Please provide the object name : ' OBJECT ==> [[ -f '' ]] ==> [[ -d '' ]]
PIPE終了ステータス
パイプを使用する場合のデフォルトの動作は、パイプ内の最後の実行コマンドの終了コードを取得することです。パイプ内の前のコマンドが失敗した場合でも、パイプの残りの部分が実行されます。
以下の例を見てください。利用できないファイルを開いて、単語数でパイプしてみました プログラム。 cat
コマンドがエラーをスローすると、単語数プログラムが実行されます。
$?
を使用して、最後に実行されたパイプコマンドの終了コードを確認しようとした場合 、単語数プログラムからの終了コードとしてゼロを取得します。
$ cat nofile.txt | wc -l cat: nofile.txt: No such file or directory 0
$ echo $? 0
スクリプトでpipefailが有効になっている場合、いずれかのコマンドがパイプにゼロ以外のリターンコードをスローすると、パイプライン全体のリターンコードと見なされます。スクリプトに次のsetプロパティを追加することで、pipefailを有効にできます。
set -o pipefail

このアプローチにはまだ問題があります。通常、パイプ内のいずれかのコマンドが失敗した場合、スクリプトはパイプ内の残りのコマンドを実行せずに終了する必要があります。
ただし、残念ながら、いずれかのコマンドが失敗した場合でも、パイプ内の後続のコマンドが実行されます。これは、パイプ内の各コマンドが独自のサブシェルで実行されるためです。シェルは、パイプ内のすべてのプロセスが完了するまで待機してから、結果を返します。
BashStrictモード
前のセクションで見た可能性のあるすべてのエラーを排除するには、すべてのスクリプトに次のオプションを追加することをお勧めします。
これらすべてのオプションについては、前のセクションですでに詳しく説明しました。
-e flag
=>コマンドがゼロ以外の終了コードをスローした場合はスクリプトを終了します。-u flag
=>未定義の変数名が使用されている場合、スクリプトを失敗させます。-
pipefail
=>パイプライン内のいずれかのコマンドが失敗した場合、終了コードはパイプライン全体で考慮されます。 -
IFS
=>内部フィールドセパレータ。改行(\ n)と(\ t)に設定すると、改行とタブでのみ分割が発生します。
set -e
set -u
set -o pipefail
または
set -euo pipefail
IFS=$'\n\t'
TRAPを使用して信号をキャプチャする
トラップ bashスクリプトへのシグナルをキャプチャし、それに応じていくつかのアクションを実行できます。
スクリプトをトリガーしたが、CTRL+C
を使用してスクリプトをキャンセルしたいシナリオを考えてみてください。 キーストローク。その場合、SIGINT
スクリプトに送信されます。この信号をキャプチャして、いくつかのコマンドまたは機能を実行できます。
以下に示す擬似コードを見てください。 SIGINT
のときに実行されるcleanupという関数を作成しました スクリプトに渡されます。
trap 'cleanup' TERM INT function cleanup(){ echo "Running cleanup since user initiated CTRL + C" <some logic> }
スクリプト内でステートメントを繰り返し実行するために使用できるトラップ「DEBUG」を使用できます。スクリプトトラップで実行される各ステートメントの動作は、関連する関数またはステートメントを実行します。
これは、以下の例を使用して理解できます。
#!/bin/bash trap 'printf "${LINENO} ==> DIR_NAME=${D_OBJECT} ; FILE_NAME=${F_OBJECT}; FILE_CREATED=${FILE_C} \n"' DEBUG read -p "Pass Dir name : " D_OBJECT read -p "Pass File name : " F_OBJECT touch ${D_OBJECT}/${F_OBJECT} && FILE_C="Yes" exit 0
これは、ユーザー入力を取得し、ファイルとディレクトリを作成する単純なプログラムです。トラップコマンドは、スクリプト内のステートメントごとに実行され、渡された引数とファイル作成ステータスを出力します。
以下の出力を確認してください。スクリプトの各行について、トラップがトリガーされ、それに応じて変数が更新されます。

詳細モードを使用してコードを印刷する
詳細モードでは、結果を返す前にコードが出力されます。プログラムがインタラクティブな入力を必要とする場合、その場合、その行だけが印刷され、その後にコードのブロックが続きます。
次のプログラムを見てください。これは、ユーザーからオブジェクトを取得し、条件ステートメントを使用して、渡されたオブジェクトがファイルまたはディレクトリであるかどうかを確認する単純なプログラムです。 。
#!/bin/bash read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT ]] then echo "$OBJECT is a directory" fiです
上記のコードを実行すると、最初にコードが出力され、次に次のようにユーザー入力を待ちます。

オブジェクトを渡すと、残りのコードが出力され、その後に出力が続きます。

set
を使用して冗長モードを設定することもできます またはshebang
。
set -v
set -o verbose
(または)
#! /bin/bash -v
詳細モードを他のモードと組み合わせることもできます。
set -vx # Verbose and Xtrace Mode
set -uv # Verbose and Unset Mode
構文検証-noexecモード
これまで、スクリプトで論理エラーを処理する方法を見てきました。このセクションでは、構文エラーについて説明します。
構文エラーはプログラムで非常に一般的です。引用符を見逃したか、ループを終了できなかった可能性があります。「-n
」を使用できます。 "noexec mode
と呼ばれるフラグ プログラムを実行する前に構文を検証します。
以下のコードを実行して、構文を検証します。
#!/bin/bash TOOLS=( htop peek tilix vagrant shutter ) for TOOL in "${TOOLS[@]" do echo "--------------INSTALLING: ${TOOL}---------------------------" apt install ${TOOL} -y #done
このプログラムには2つのエラーがあります。まず、「for loop
」の中括弧を閉じることができませんでした "そして2番目にdone
ループの終わりを示すキーワードがコメント化されています。
このプログラムを実行すると、中括弧がないことを示す次のエラーメッセージが表示されます。 およびキーワードの実行 。エラーメッセージで示されている行番号に、実際のエラーを見つけるために掘り下げる必要のあるエラーが含まれていない場合があります。
$ bash -n ./debugging.sh ./debugging.sh: line 6: unexpected EOF while looking for matching `"' ./debugging.sh: line 8: syntax error: unexpected end of file
デフォルトでは、スクリプトを実行すると、bashは構文を検証し、noexecモードを使用しなくてもこれらのエラーをスローすることに注意してください。
または、set
を使用することもできます noexec
を使用するコマンドまたはshebang モード。
set -n set -o noexec
または、
#! /bin/bash -n
スクリプトのデバッグに使用される、一見の価値のある外部ツールがいくつかあります。そのようなツールの1つがシェルチェックです。 。 Shellcheckは、vscode、sublime text、Atomなどの一般的なテキストエディターと統合することもできます。
結論
この記事では、bashスクリプトをデバッグする方法のいくつかを紹介しました。他のプログラミング言語とは異なり、bashにはいくつかの組み込みオプション以外のデバッグツールはありません。場合によっては、これらの組み込みのデバッグオプションで、作業を完了するのに十分すぎることがあります。
Bashスクリプトガイド:
- Bashスクリプト–getoptsを使用してBashスクリプトの引数を解析する
- LinuxおよびUnixでZenityを使用してBashスクリプトでGUIダイアログボックスを作成する方法
- Bashスクリプティング–ケースステートメント
- Bashスクリプティング–条件付きステートメント
- Bashスクリプティング–文字列操作
- Bashスクリプティング–例を使用して説明されたPrintfコマンド
- Bashスクリプティング–例を使用して説明されたインデックス付き配列
- Bashスクリプティング–例を使用して説明された連想配列
- Bashスクリプティング–例で説明されているForループ
- Bashスクリプティング–ループの説明中およびループまで
- 例を使用して説明されたBashリダイレクト
- Bashスクリプティング–例で説明されている変数
- Bashスクリプト–例で説明されている関数
- Linuxの例で説明されているBashEchoコマンド
- 初心者向けのBashヒアドキュメントチュートリアル