views:

903

answers:

5

Is there any way to debug a bash script? E.g something that prints a sort of execution log like "calling line 1", "calling line 2" etc.

+11  A: 
sh -x script [arg1 ...]
bash -x script [arg1 ...]

These give you a trace of what is being executed. (See also 'Clarification' near the bottom of the answer.)

Sometimes, you need to control the debugging within the script. In that case, as Cheeto reminded me, you can use:

set -x

This turns debugging on. You can then turn it off again with:

set +x

Also, shells generally provide options '-n' for 'no execution' and '-v' for 'verbose' mode; you can use these in combination to see whether the shell thinks it could execute your script - occasionally useful if you have an unbalanced quote somewhere.


There is contention that the '-x' option in Bash is different from other shells (see the comments). The Bash Manual says:

  • -x

    Print a trace of simple commands, for commands, case commands, select commands, and arithmetic for commands and their arguments or associated word lists after they are expanded and before they are executed. The value of the PS4 variable is expanded and the resultant value is printed before the command and its expanded arguments.

That much does not seem to indicate different behaviour at all. I don't see any other relevant references to '-x' in the manual. It does not describe differences in the startup sequence.

Clarification: On systems such as a typical Linux box, where '/bin/sh' is a symlink to '/bin/bash' (or to any Bash executable), the two command lines achieve the identical effect. On other systems (for example, Solaris), /bin/sh is not Bash, and the two command lines would give (slightly) different results; most notably, '/bin/sh' would be confused by constructs in Bash that it does not recognize at all. When invoked by name like this, the 'shebang' line ('#!/bin/bash' vs '#!/bin/sh') at the start of the file has no effect on how the contents are interpreted. I've not found anything in the Bash Manual that indicates different behaviour from Bash depending on whether it is invoked as 'sh' or 'bash'.

Jonathan Leffler
He did specify a `bash` script. And running a bash script with `sh -x` will cause it to behave completely different! Please update your answer.
lhunath
@lhunath: In what way does 'sh -x' (or 'bash -x') make a script behave completely differently? Obviously, it outputs trace information to stderr; that's a given (though not mentioned in my answer). But what else? I use 'bash' as 'sh' on Linux and MacOS X and haven't noticed a serious issue.
Jonathan Leffler
There are differences, in startup and under runtime. They're fully documented in the Bash distribution.
TheBonsai
Let me clarify: Running a `bash` script with `sh` causes the interpreter to disable (almost) all bash-features, leaving only the POSIX ones. Since OP said his script was a bash script, it should not be ran with sh. If it is, masses of errors will follow; unexpected behaviour; and depending on the script, really bad stuff could happen like files getting deleted and so on.
lhunath
Here's a link to the bash doc: http://www.gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files'If Bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the posix standard as well'
thethinman
+3  A: 

You can also write "set -x" within the script.

Cheeto
And you can write 'set +x' to turn it off.
Jonathan Leffler
+2  A: 

BASH Debugger

seb
A: 

I've used the following methods to debug my script.

set -e makes the script stop immediately if any external program returns a non-zero exit status. This is useful if your script attempts to handle all error cases and where a failure to do so should be trapped.

set -x was mentioned above and is certainly the most useful of all the debugging methods.

set -n might also be useful if you want to check your script for syntax errors.

strace is also useful to see what's going on. Especially useful if you haven't written the script yourself.

Stracing a script (i.e. stracing a shell executing the script) is a strange shell debugging method (but may work for a limited set of issues).
TheBonsai
I admit it is strange and also very verbose, but if you limit the output of strace to a few syscalls, it becomes useful.
A: 

Some assorted comments:

http://bash-hackers.org/wiki/doku.php/scripting/debuggingtips

TheBonsai