How to echo commands in a bash shell script, but not execute them?

Is there a way for running a shell script with echoing the commands but w/o actually executing them?

Let's say I have script removing a file whose name is stored in a variable:

#!/bin/bash
set -v
FN="filename"
rm -f ${FN}

Adding set -v will echo the following commands before execution:

$ ./scr.sh
FN="filename"
rm -f ${FN}

Now, I want to see the flow of this script w/o actually removing the file. IOW, I want to prevent any effect on the external environment and filesystem. Is this possible?

I could wrap all commands with an echo command, but it is tiring for a long script.


There's no way to step through a script to see how it would execute without actually doing that. In your example, there are no if statements or loops. But in real scripts, there are often lots of conditional statements. Which branch will get taken will often depend on what happened when the shell ran the previous command. If it doesn't run the command, there's no way for the shell to know what output it would have generated or what the return code would have been, which the next conditional branch or assignment statement might depend on.

If the point is that you'd like to scrutinize a script and know what it does before you run it, that's not a bad idea. But realistically, about the best way to do that is by just browsing the file with less or vi or something similar.

Added

If you're developing a script and you're wanting to step through it the first time, testing the logic but not actually doing any damage if you've got a bug, the solution I'm often able to use is to modify only the statements that could do any damage by pasting an echo onto the front.

This often works in typical real-life scripts because (a) generating the lists of items you'll iterate over or the value to which you'll set a variable can often be generated without changing the filesystem and (b) it's usually sufficient to assume that if you did run the command, it would succeed.


I think you are going to have to echo - however if you put the command in a variable you can turn it on and off. Also, the command can be a function and as sophisticated as you want.

#!/bin/bash
echo 'Debug'
  D=echo
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy
echo $'\n\nLive'
  D=
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy

==================================================

!$ > ./conditional.sh
Debug
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy
rm -f testy
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy

Live
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy
ls: cannot access testy: No such file or directory

You an trace the flow using the -x option for bash, but this would still execute the commands.

The best you could do is to just put echo or comment out the commands that have external effects like the rm. At least you wouldn't have to change every line.