bashスクリプトをデバッグする方法は?[閉まっている]


159

bashスクリプトをデバッグする方法はありますか?たとえば、「calling line 1」、「calling line 2」などのような実行ログを出力するものです。



回答:


195
sh -x script [arg1 ...]
bash -x script [arg1 ...]

これらは、実行中のトレースを提供します。(回答の下部にある「説明」も参照してください。)

場合によっては、スクリプト内でデバッグを制御する必要があります。その場合、チート 私に思い出させたように、あなたは使うことができます:

set -x

これにより、デバッグがオンになります。その後、次のコマンドでオフにできます。

set +x

$-現在のフラグを分析することにより、現在のトレース状態を確認できます。x。)

また、シェルは通常-n、「実行なし」のオプション「-v」と「冗長」モードのオプション「」を提供します。これらを組み合わせて使用​​することで、シェルがスクリプトを実行できるとシェルが判断したかどうかを確認できます。


-xBashの' 'オプションは他のシェルとは異なるという意見があります(コメントを参照)。Bashのマニュアルは言います:

  • -バツ

    単純なコマンド、forコマンド、caseコマンド、selectコマンド、および算術forコマンドと、それらの引数または関連する単語リストのトレースを、それらが展開されてから実行される前に出力します。PS4変数の値が展開され、結果の値がコマンドとその展開された引数の前に出力されます。

それだけではまったく異なる動作を示しているようには見えません。-xマニュアルに他の「」への参照がありません。起動シーケンスの違いについては説明しません。

明確化:「/bin/sh」が「」へのシンボリックリンクである典型的なLinuxボックスなどのシステム/bin/bash(またはBash実行可能ファイルが検出された場所)では、2つのコマンドラインは、実行トレースをオンにしてスクリプトを実行するのと同等の効果を実現します。他のシステム(たとえば、Solaris、およびLinuxの最新のバリアント)では、/bin/shBashではないため、2つのコマンドラインは(わずかに)異なる結果をもたらします。最も注目すべきは、 ' /bin/sh'がまったく認識されないBashの構成要素と混同されることです。(Solarisでは/bin/sh、Bourneシェルです。最新のLinuxでは、Dashになることがあります。これは、より小さく、厳密にはPOSIXのみのシェルです。)このような名前で呼び出されると、 'shebang'行( ' #!/bin/bash' vs '#!/bin/sh'

BashのマニュアルにはBash POSIXモードに関するセクションがあり、この回答の長い間誤ったバージョン(以下のコメントも参照)とは異なり、「Bashが呼び出されたsh」と「Bashが呼び出された」の違いについて詳しく説明していますbash'。

(Bash)シェルスクリプトをデバッグするときは、-xオプションを指定してシバン行で指定されたシェルを使用することが賢明であり、正気です。そうしないと、デバッグ時とスクリプト実行時の動作が異なる可能性があります(?)。


1
彼はbashスクリプトを指定しました。でbashスクリプトを実行するsh -xと、動作がまったく異なります!回答を更新してください。
lhunath 2009年

1
@lhunath: 'sh -x'(または 'bash -x')はどのようにスクリプトの動作をまったく異なりますか?明らかに、それはstderrにトレース情報を出力します。それは与えられたものです(私の答えでは言及されていません)。しかし、他に何ですか?LinuxとMacOS Xでは「bash」を「sh」として使用していますが、深刻な問題に気づいていません。
ジョナサンレフラー

6
起動時と実行時では違いがあります。それらはBashディストリビューションに完全に文書化されています。
TheBonsai 2009年

4
ここでは、bashのドキュメントへのリンクがあります:gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files「Bashのが名前のshで呼び出された場合、それが模倣するのshの歴史的なバージョンなどの起動時の動作を試みますできるかぎり、「だけでなく、POSIX標準に準拠しながら、
thethinman

6
など多くの有用な情報を提供するためのプロンプトPS4使用:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani

28

次の方法でスクリプトをデバッグしました。

set -e外部プログラムがゼロ以外の終了ステータスを返した場合、スクリプトをすぐに停止させます。これは、スクリプトがすべてのエラーケースを処理しようとする場合、および処理の失敗をトラップする必要がある場合に役立ちます。

set -x は前述したとおり、すべてのデバッグ方法の中で最も有用です。

set -n スクリプトの構文エラーをチェックする場合にも役立ちます。

strace何が起こっているかを確認するのにも役立ちます。スクリプトを自分で作成していない場合に特に便利です。


1
スクリプトの紐付け(つまり、スクリプトを実行するシェルの紐付け)は、奇妙なシェルのデバッグ方法です(ただし、限られた一連の問題で機能する場合があります)。
TheBonsai 2009年

1
私はそれが奇妙で非常に冗長であることを認めますが、straceの出力をいくつかのsyscallsに制限すると、便利になります。

1
strace -fスクリプトによって開始されたプロセスのエラーも検出したい場合は、これが必要であることに注意してください。(これにより何倍も冗長になりますが、興味のあるシステムコールに限定すればなお便利です)。
Random832


12

この回答は有効で便利です:https : //stackoverflow.com/a/951352

しかし、「標準的な」スクリプトのデバッグ方法は非効率的で直感的ではなく、使いにくいことがわかりました。すべてをあなたの指先に置き、簡単な問題(そして難しい問題の可能性)のために仕事を簡単にする洗練されたGUIデバッガに慣れている人にとって、これらのソリューションはあまり満足のいくものではありません。

私がしていることは、DDDとbashdbを組み合わせて使用​​することです。前者は後者を実行し、後者はスクリプトを実行します。これにより、マルチウィンドウUIにコンテキスト内のコードをステップ実行し、変数やスタックなどを表示する機能が提供されます。頭の中でコンテキストを維持したり、ソースを再リストしたりするための一定の精神的な努力は必要ありません。

これを設定するためのガイダンスがあります:http : //ubuntuforums.org/showthread.php?t=660223


ちょうどあなたの答えのおかげでdddを発見しました。Ubuntu 12.04.3(64ビット)では、apt-sourcesバージョンは機能しません。bashスクリプトのデバッグを開始するには、ソースからコンパイルしてインストールする必要がありました。ここの指示-askubuntu.com/questions/156906/…が役に立ちました。
クロノデカール2013年

はい、それは問題です。(回答は今、この情報に編集されている)など、「dddbash」インストール/ DDDビルド、その間違った場合は、古いバージョンを削除し、bashdbをインストールする-私はいくつかのスクリプトでそれにいくつかの時間の背中を解決
Stabledog


10

私はshellcheckユーティリティを見つけました、そしてそれが興味深いhttps://github.com/koalaman/shellcheckだと思う人もいるかもしれません

小さな例:

$ cat test.sh 
ARRAY=("hello there" world)

for x in $ARRAY; do
  echo $x
done

$ shellcheck test.sh 

In test.sh line 3:
for x in $ARRAY; do
         ^-- SC2128: Expanding an array without an index only gives the first element.

バグを修正し、最初に試してください...

$ cat test.sh       
ARRAY=("hello there" world)

for x in ${ARRAY[@]}; do
  echo $x
done

$ shellcheck test.sh

In test.sh line 3:
for x in ${ARRAY[@]}; do
         ^-- SC2068: Double quote array expansions, otherwise they're like $* and break on spaces.

もう一度やってみましょう...

$ cat test.sh 
ARRAY=("hello there" world)

for x in "${ARRAY[@]}"; do
  echo $x
done

$ shellcheck test.sh

今見つけて!

ほんの小さな例です。


1
そしてそれはオンラインです!
Nick Westgate 2016

幸いなことに、ツールは進化して、残りのバグも検出されるようになりました。
Tripleee 2017年

3

VSCodeをインストールし、bashデバッグ拡張機能を追加すると、ビジュアルモードでデバッグする準備が整います。こちらの動作をご覧ください。

ここに画像の説明を入力してください


3

プラグインシェルとbasheclipseでeclipseを使用します。

https://sourceforge.net/projects/shelled/?source=directory https://sourceforge.net/projects/basheclipse/?source=directory

シェルの場合:zipをダウンロードして、ヘルプを介してEclipseにインポートします->新しいソフトウェアをインストールします:ローカルアーカイブbasheclipseの場合:jarをeclipseのdropinsディレクトリにコピーします

手順に従ってくださいhttps://sourceforge.net/projects/basheclipse/files/?source=navbar

ここに画像の説明を入力してください

多くのスクリーンショットを含むチュートリアルをhttp://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.htmlで書きました


2
これは境界線のリンクのみの回答ですこちらも参照)。できる限り多くの情報を含めるように回答を拡張する必要があります。少なくとも、提案していることを実際に達成するために最低限必要な情報を提供し、参照用にのみリンクを使用してください。基本的に、Stack Overflow(およびすべてのStack Exchange)への投稿は自己完結型である必要があります。つまり、読者が指示のために現場を離れる必要がないように、十分な情報を回答に含める必要があります。今のところ、この答えはそうではありません。
Makyen

これは、実際に真のデバッグが可能であることを実際に示している多くのことを調べた後、私が見つけた最初の答えです。標準的な回答 "set + x"は、自己完結型の回答と完全に一致しますが、真のデバッグに関する真の質問をほとんど気にせずに無視します。私はこの答え👏拍手
simbo1905

2

Bashデバッガーをビルドしました。試してみてください。それがhttps://sourceforge.net/projects/bashdebugingbashに役立つことを願ってい ます


BDBは現在、英語とスペイン語でサポートされています。言語を変更するには、ファイル/ etc / default / bdbを編集します
abadjm

スクリーンショットは興味深いように見えますが、「bdb.sh:行32:bdbSTR [1]:バインドされていない変数」を実行させることはできませんでした。ところで、コードで実行する各ステップで、設定されているすべての変数の現在の値が表示されますか?
Aquarius Power

2

+ x = @ECHO OFFを設定し、-x = @ECHO ONを設定します。


-xv次のように、オプションを標準シバンに追加できます。

#!/bin/bash -xv  

-x:実行時にコマンドとその引数を表示します。
-v:読み取られたシェル入力行を表示します。


ltraceは、に似た別のLinuxユーティリティstraceです。ただし、ltrace実行可能ファイルまたは実行中のプロセスで呼び出されているすべてのライブラリ呼び出しをリストします。その名前自体は、ライブラリ呼び出しトレースに由来しています。例えば:

ltrace ./executable <parameters>  
ltrace -p <PID>  

ソース



1

デバッグするためのいくつかのトリック スクリプト:

使用する set -[nvx]

に加えて

set -x

そして

set +x

ダンプを停止します。

set -vダンプが小さいほど、出力が大きくならないことについてお話します。

bash <<<$'set -x\nfor i in {0..9};do\n\techo $i\n\tdone\nset +x' 2>&1 >/dev/null|wc -l
21

for arg in x v n nx nv nvx;do echo "- opts: $arg"
    bash 2> >(wc -l|sed s/^/stderr:/) > >(wc -l|sed s/^/stdout:/) <<eof
        set -$arg
        for i in {0..9};do
            echo $i
          done
        set +$arg
        echo Done.
eof
    sleep .02
  done
- opts: x
stdout:11
stderr:21
- opts: v
stdout:11
stderr:4
- opts: n
stdout:0
stderr:0
- opts: nx
stdout:0
stderr:0
- opts: nv
stdout:0
stderr:5
- opts: nvx
stdout:0
stderr:5

変数のダンプまたはオンザフライでのトレース

いくつかの変数をテストするために、私はいつかこれを使用します:

bash <(sed '18ideclare >&2 -p var1 var2' myscript.sh) args

追加用:

declare >&2 -p var1 var2

18行目で、スクリプトを実行し(argsを使用)、編集する必要はありません。

もちろん、これを追加するために使用できますset [+-][nvx]

bash <(sed '18s/$/\ndeclare -p v1 v2 >\&2/;22s/^/set -x\n/;26s/^/set +x\n/' myscript) args

declare -p v1 v2 >&218行目以降、set -x22行目前、set +x26行目前に追加されます。

小さなサンプル:

bash <(sed '2,3s/$/\ndeclare -p LINENO i v2 >\&2/;5s/^/set -x\n/;7s/^/set +x\n/' <(
        seq -f 'echo $@, $((i=%g))' 1 8)) arg1 arg2
arg1 arg2, 1
arg1 arg2, 2
declare -i LINENO="3"
declare -- i="2"
/dev/fd/63: line 3: declare: v2: not found
arg1 arg2, 3
declare -i LINENO="5"
declare -- i="3"
/dev/fd/63: line 5: declare: v2: not found
arg1 arg2, 4
+ echo arg1 arg2, 5
arg1 arg2, 5
+ echo arg1 arg2, 6
arg1 arg2, 6
+ set +x
arg1 arg2, 7
arg1 arg2, 8

注:ケアについて$LINENOの影響を受けることになるオンザフライで変更を!

(実行中の結果のスクリプトを確認するには、単にドロップbash <(して) arg1 arg2

ステップバイステップ、実行時間

bashスクリプトのプロファイリング方法に関する私の答えを見てください


0

シェルのグローバル変数を介したシェルスクリプトのロギングについては、かなりの詳細があります。シェルスクリプトで同様の種類のロギングをエミュレートできます。http//www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html

この投稿には、INFO、DEBUG、ERRORなどのログレベルの紹介に関する詳細があります。スクリプトのエントリ、スクリプトの終了、関数のエントリ、関数の終了などの詳細のトレース。

サンプルログ:

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.