From: R. Bernstein on
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!
From: invincible on
On 19 Jun, 08:02, ro...(a)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
>
> 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!

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

Ciao
From: mop2 on
On Fri, 20 Jun 2008 09:58:41 -0300, invincible <imanuk2007(a)googlemail.com> wrote:

> On 19 Jun, 08:02, ro...(a)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
From: R. Bernstein on
mop2 <invalid(a)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.
From: invincible on
Hello R.Bernstein,

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

Ciao