Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: How To Debug a Running Shell Script

9 views
Skip to first unread message

R. Bernstein

unread,
Jun 19, 2008, 3:02:43 AM6/19/08
to
A little while back someone asked about debugging a running shell
script. (Alas, the post from less than 3 weeks ago has expired in my
news reader.)

An acceptable solution was proposed which periodically reads a file
that controls turning on some debugging switches.

Another variation on that idea is to install a signal handler. This
has an advantage of not requiring any sort of polling which means the
debugging will have a more instantaneous effect, doesn't have to
appear in a loop or appear more than once or other than at the beginning
of the file.

Here's an example. In file debugit.sh:

# This is my extra debug hook
trap 'set -x' USR1 ; trap 'set +x' USR2

echo $$
while : ; do
date=$(date)
echo "$date"
sleep 2
done


Now run:

$ bash debugit.sh
9386
Thu Jun 19 02:31:09 EDT 2008
Thu Jun 19 02:31:11 EDT 2008

From some other shell:
kill -USR1 9386

And back to the running program...

(debugit.sh:5): - [4,0]
:
((debugit.sh:6): - [4,1]
date
(debugit.sh:6): - [4,0]
date='Thu Jun 19 02:31:19 EDT 2008'
(debugit.sh:7): - [4,0]
echo 'Thu Jun 19 02:31:19 EDT 2008'
Thu Jun 19 02:31:19 EDT 2008
(debugit.sh:8): - [4,0]
sleep 2
(debugit.sh:5): - [4,0]
:
((debugit.sh:6): - [4,1]
date
(debugit.sh:6): - [4,0]
date='Thu Jun 19 02:31:21 EDT 2008'
(debugit.sh:7): - [4,0]
echo 'Thu Jun 19 02:31:21 EDT 2008'
Thu Jun 19 02:31:21 EDT 2008
(debugit.sh:8): - [4,0]
sleep 2
((debugit.sh:9): - [4,0]

To turn off debugging:
kill -USR2 9386

set +x
Thu Jun 19 02:31:23 EDT 2008
Thu Jun 19 02:31:25 EDT 2008
...

In the above listing, my bash-specific PS4 setting is:

declare -x PS4="(\${BASH_SOURCE}:\${LINENO}): \${FUNCNAME[0]} - [\${SHLVL},\${BASH_SUBSHELL}]\\n"

This works best for version 3.0 and above.

Going further, if you've got the bash debugger (http://bashdb.sf.net)
installed, it comes with a hook to allow it to get called when an
interrupt is given to the program. Find the file bashdb-trace
installed on your system. On my Ubuntu box, Debian bashdb package
installs it in /usr/share/bashdb/bashdb-trace. Now change your program
like this:

# This is my extra debug hook
source /usr/share/bashdb/bashdb-trace

echo $$
while : ; do
date=$(date)
echo "$date"
sleep 2
done

And run:

bash ./debugit2.sh
Bourne-Again Shell Debugger, release bash-3.1-0.08
Copyright 2002, 2003, 2004, 2006 Rocky Bernstein
This is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.

9435
Thu Jun 19 02:43:06 EDT 2008
Thu Jun 19 02:43:08 EDT 2008

Sent it an "interrupt" signal
kill -INT 9435

And back to the running program:

Program received signal SIGINT (2)...
->0 in file `./debugit2.sh' at line 251 # not sure where 251 came from!
##1 main() called from file `./debugit2.sh' at line 0
bashdb<0> where
->0 in file `./debugit2.sh' at line 9 # but this line number is now right
##1 main() called from file `./debugit2.sh' at line 0
bashdb<1> list 1
1: # This is my extra debug hook
2: source /usr/share/bashdb/bashdb-trace
3:
4: echo $$
5: while : ; do
6: date=$(date)
7: echo "$date"
8: sleep 2
9:==>done
bashdb<2> s
(./debugit2.sh:5):
5: while : ; do
bashdb<3> s
(./debugit2.sh:6):
6: date=$(date)
bashdb<4>

Some of this is described in the bashdb manual:
http://bashdb.sourceforge.net/bashdb.html#SEC10

The hooks and the debugger in general are not as robust as I would
like -- feel free to contribute!

invincible

unread,
Jun 20, 2008, 8:58:41 AM6/20/08
to

Thats was me and many thanx for your help. I would come back to you
soon on this.

Ciao

mop2

unread,
Jun 20, 2008, 8:30:25 PM6/20/08
to
On Fri, 20 Jun 2008 09:58:41 -0300, invincible <imanu...@googlemail.com> wrote:

> On 19 Jun, 08:02, ro...@panix.com (R. Bernstein) wrote:
>> A little while back someone asked about debugging a running shell
>> script. (Alas, the post from less than 3 weeks ago has expired in my
>> news reader.)
>>
>> An acceptable solution was proposed which periodically reads a file
>> that controls turning on some debugging switches.
>>
>> Another variation on that idea is to install a signal handler. This
>> has an advantage of not requiring any sort of polling which means the
>> debugging will have a more instantaneous effect, doesn't have to
>> appear in a loop or appear more than once or other than at the beginning
>> of the file.
>>
>> Here's an example. In file debugit.sh:
>>
>> # This is my extra debug hook
>> trap 'set -x' USR1 ; trap 'set +x' USR2
>>

>>


>> From some other shell:
>> kill -USR1 9386
>>

>>


>> To turn off debugging:
>> kill -USR2 9386
>>

>


> Thats was me and many thanx for your help. I would come back to you
> soon on this.
>
> Ciao
>

Hi,
another idea using ^C - = q (set -x, set +x, exit)

trap 'read -n1 a;case "$a" in q)exit;;-)set -x;;=)set +x;esac' 2

R. Bernstein

unread,
Jun 22, 2008, 12:17:33 AM6/22/08
to
mop2 <inv...@mail.address> writes:

> Hi,
> another idea using ^C - = q (set -x, set +x, exit)
>
> trap 'read -n1 a;case "$a" in q)exit;;-)set -x;;=)set +x;esac' 2

This is cool. I'd probably add a prompt before the read, and the -n1
option doesn't seem to be in POSIX (for those of you who use
dash/ash).

More serious though is that one may or may not have access to
stdin, e.g. if your script is running as a daemon. So the other code
may still be preferable in that kind of situation.

And here's yet another variation which eliminates the need to modify the
script. Put the following in a file, say "debug_wrapper":

# adjust trap as suggested above


trap 'set -x' USR1 ; trap 'set +x' USR2

source "$@"

Then run run your program:
debug_wrapper my_program

With all of the variation given, you have an instant debugger. ;-)

But there are a couple of thing problems of the "source" method. If
the program you are running uses $0 it will report your debug_wrapper
rather than itself. Probably in the next release of bashdb I'll add a
built-in command to set $0; bashdb or such a wrapper above could then
use that to hide itself a little bit more.

Second, the stack nesting will be a little different. In another
posting I showed how you could tell if your program was source'd or
not and this change will confuse something like this.

invincible

unread,
Jun 26, 2008, 12:01:33 PM6/26/08
to
Hello R.Bernstein,

Just wanted to know if the above explantion is just valid on bash
shell. as I currently operate on Korn .

Ciao

Joachim Schmitz

unread,
Jun 26, 2008, 12:57:43 PM6/26/08
to
Parts of it are pure bash, e.g. BASH_SOURCE and BASH_SUBSHELL, other parts
apply to Korn Shell too

Bye, Jojo


0 new messages