without - shell script verbose

How to echo shell commands as they are executed? (10)

In a shell script how do I echo all shell commands called and expand any variable names? For example, given the following line:


I would like the script to run the command and display the following

ls /full/path/to/some/dir

The purpose is to save a log of all shell commands called and their arguments. Perhaps there is a better way of generating such a a log?

set -x or set -o xtrace expands variables and prints a little + sign before the line.

set -v or set -o verbose does not expand the variables before printing.

Use set +x and set +v to turn off the above settings.

On the first line of the script, one can put #!/bin/sh -x (or -v) to have the same effect as set -x (or -v) later in the script.

The above also works with /bin/sh.


$ cat shl

ls $DIR

$ bash -x shl 
+ DIR=/tmp/so
+ ls /tmp/so

set -x will give you what you want.

Here is an example shell script to demonstrate:

set -x #echo on

ls $PWD

This expands all variables and prints the full commands before output of the command.


+ ls /home/user/
file1.txt file2.txt

For csh and tcsh, you can set verbose or set echo (or you can even set both, but it may result in some duplication most of the time).

The verbose option prints pretty much the exact shell expression that you type.

The echo option is more indicative of what will be executed through spawning.



Special shell variables

verbose If set, causes the words of each command to be printed, after history substitution (if any). Set by the -v command line option.

echo If set, each command with its arguments is echoed just before it is executed. For non-builtin commands all expansions occur before echoing. Builtin commands are echoed before command and filename substitution, because these substitutions are then done selectively. Set by the -x command line option.

I use a function to echo then run the command

#function to display commands
exe() { echo "\$ [email protected]" ; "[email protected]" ; }

exe echo hello world

Which outputs

$ echo hello world
hello world


For more complicated commands pipes etc you can use eval:

#function to display commands
exe() { echo "\$ ${@/eval/}" ; "[email protected]" ; }

exe eval "echo 'Hello World' | cut -d ' ' -f1"

Which outputs

$  echo 'Hello World' | cut -d ' ' -f1

Someone above posted:

#function to display commands
exe() { echo "\$ [email protected]" ; "[email protected]" ; }

and this looks promising, but I can't for the life of me figure out what it does. I've googled and searched in the man bash page for "\$" and "[email protected]", and find absolutely nothing.

I understand a function is being created, named "exec()". I understand the curly-brackets mark the beginning and end of the function. I think I understand that the semi-colon marks a "hard return" between a multi-line command, so that '{ echo "\$ [email protected]" ; "[email protected]" ; }' becomes, in essence:

echo "\$ [email protected]"
"[email protected]"


Can any one give me a brief explanation, or where to find this info, since obviously my google-fu is failing me?

(Without meaning to start a new question on an old thread, my goal is to reroute the output to a file. The "set -x ; [commands] ; set +x" method would work adequately well for me, but I can't figure out how to echo the results to a file instead of the screen, so I was trying to understand this other method in hopes I could use me very poor understanding of redirection/pipes/tee/etc to do the same thing.)



With some tinkering, I believe I figured it out. Here's my equivalent code for what I'm needing:

exe () {
  params="[email protected]"                       # Put all of the command-line into "params"
  printf "%s\t$params" "$(date)" >> "$SCRIPT_LOG"   # Print the command to the log file
  $params                           # Execute the command

exe rm -rf /Library/LaunchAgents/offendingfile
exe rm -rf /Library/LaunchAgents/secondoffendingfile

The results in the logfile.txt look something like:

Tue Jun  7 16:59:57 CDT 2016  rm -rf /Library/LaunchAgents/offendingfile
Tue Jun  7 16:59:57 CDT 2016  rm -rf /Library/LaunchAgents/secondoffendingfile

Just what I needed. Thanks!

Type "bash -x" on the command line before the name of the bash script. For instance, to execute foo.sh, type:

bash -x foo.sh

You can execute a bash script in debug mode with the -x option.
This will echo all the commands.

bash -x example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt

You can also save the -x option in the script. Just specify the -x option in the shebang.

######## example_script.sh ###################
#!/bin/bash -x

cd /home/user
mv text.txt mytext.txt



# Console output
+ cd /home/user
+ mv text.txt mytext.txt

shuckc's answer for echoing select lines has a few downsides: you end up with the following set +x command being echoed as well, and you lose the ability to test the exit code with $? since it gets overwritten by the set +x.

Another option is to run the command in a subshell:

echo "getting URL..."
( set -x ; curl -s --fail $URL -o $OUTFILE )

if [ $? -eq 0 ] ; then
    echo "curl failed"
    exit 1

which will give you output like:

getting URL...
+ curl -s --fail http://example.com/missing -o /tmp/example
curl failed

This does incur the overhead of creating a new subshell for the command, though.

$ cat exampleScript.sh
echo $name;

bash -x exampleScript.sh

Output is as follows: