GNU/Linux >> Linux の 問題 >  >> Linux

LinuxおよびUnixでBashスクリプトをデバッグする方法

デバッグは、プログラムのエラーを修正するのに役立ちます。この記事では、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ヒアドキュメントチュートリアル

Linux
  1. Linuxで静的IPアドレスを設定してネットワークを構成する方法

  2. Linux で環境変数を設定、一覧表示、および削除する方法

  3. UNIX / Linux :mutt のインストールと設定方法

  1. Linuxで環境変数を設定および一覧表示する方法

  2. Linuxで環境変数とシェル変数を設定/作成する方法

  3. Linux/Unix で $PATH を永続的に設定するには?

  1. LinuxにTorブラウザをインストールして設定する方法

  2. Linuxで環境変数を設定および一覧表示する方法

  3. LinuxおよびUnixでZenityを使用してBashスクリプトでGUIダイアログボックスを作成する方法