There's a bash debugger, bashdb, which is an installable package on many distros. It's a shell script thatIt uses bash's built-in extended debugging capabilities. It's an installable package in many distrosmode (shopt -s extdebug). It looks a lot like gdb; here's a sample session to give some flavor:
$ ls 1st.JPG 2ndJPG.JPG $ cat ../foo.sh for f in *.JPG do newf=${f/JPG/jpg} mv $f $newf done $ bashdb ../foo.sh (foo.sh:1): 1: for f in *.JPG bashdb<0> next (foo.sh:3): 3: newf=${f/JPG/jpg} bashdb<1> next (foo.sh:4): 4: mv $f $newf As in gdb, the statement is shown just before it is about to be executed. So we can examine variables to see what the statement will do before it does it.
bashdb<2> print $f $newf 1st.JPG 1st.jpg bashdb<3> next (foo.sh:1): 1: for f in *.JPG bashdb<4> next (foo.sh:3): 3: newf=${f/JPG/jpg} bashdb<5> next (foo.sh:4): 4: mv $f $newf bashdb<6> print $f $newf 2ndJPG.JPG 2ndjpg.JPG That's not what we want! Let's look at the parameter expansion again.
bashdb<7> print $f ${f/JPG/jpg} 2ndJPG.JPG 2ndjpg.JPG bashdb<8> print $f ${f/JPG$/jpg} 2ndJPG.JPG 2ndJPG.JPG bashdb<9> print $f ${f/%JPG/jpg} 2ndJPG.JPG 2ndJPG.jpg OK, that works. Let's set newf to the correct value.
bashdb<10> eval newf=${f/%JPG/jpg} $? is 0 bashdb<11> print $f $newf 2ndJPG.JPG 2ndJPG.jpg Looks good. Continue the script.
bashdb<12> next Debugged program terminated normally. Use q to quit or R to restart. $ ls 1st.jpg 2ndJPG.jpg