The outputs are very similar for simple commands, but it seems that set -v
(verbose) simply repeats the input line, while set -x
(xtrace) shows the command(s) that are run after variable expansions and word splitting, etc. Considering the examples below, it seems to me that it's worth using both when debugging shell scripts: verbose helps navigate the script and show the intention of the commands, while xtrace shows in more detail what is actually being run. I'm going to use set -vx
when debugging scripts from now on. The differences become more obvious in examples with variables, command lists, functions, etc:
$ set +vx # both disabled (default for most people)
$ foo=(1 2 '3 three')
$ printf 'foo is %s\n' "${foo[@]}" && echo ''
foo is 1
foo is 2
foo is 3 three
$ set -v # verbose
$ printf 'foo is %s\n' "${foo[@]}" && echo ''
printf 'foo is %s\n' "${foo[@]}" && echo ''
foo is 1
foo is 2
foo is 3 three
$ set +v
set +v
$ set -x # xtrace
$ printf 'foo is %s\n' "${foo[@]}" && echo ''
+ printf 'foo is %s\n' 1 2 '3 three'
foo is 1
foo is 2
foo is 3 three
+ echo ''
$ set +x
+ set +x
$ set -vx # both verbose and xtrace
$ printf 'foo is %s\n' "${foo[@]}" && echo ''
printf 'foo is %s\n' "${foo[@]}" && echo '' # from verbose, input line simply repeated
+ printf 'foo is %s\n' 1 2 '3 three' # from xtrace, command list split, variables substituted
foo is 1
foo is 2
foo is 3 three
+ echo ''
# word splitting behaviour is made more obvious by xtrace
# (note the array is unquoted now)
$ printf 'foo is %s\n' ${foo[@]} && echo ''
printf 'foo is %s\n' ${foo[@]} && echo ''
+ printf 'foo is %s\n' 1 2 3 three # missing single quotes due to word splitting
foo is 1
foo is 2
foo is 3
foo is three # !
+ echo ''
# function with both verbose and xtrace set
$ function bar { printf '%s\n' "${foo[@]}"; }
function bar { printf '%s\n' "${foo[@]}"; } # verbose repeats definition, nothing output by xtrace
$ bar
bar # verbose repeats function call
+ bar # xtrace shows commands run
+ printf '%s\n' 1 2 '3 three'
1
2
3 three
Aside: other shells
The above examples are from bash
. In my testing, the output of posix dash
for both options is very similar, although of course no arrays are possible in that shell. zsh
expands the xtrace output slightly by prepending with a line number, but otherwise behaves very similarly (although here, its different word splitting behaviour is apparent):
$ zsh
% foo=(1 2 '3 three')
% set -vx
% printf 'foo is %s\n' ${foo[@]} && echo ''
printf 'foo is %s\n' ${foo[@]} && echo '' # verbose repeats input command
+zsh:14> printf 'foo is %s\n' 1 2 '3 three' # xtrace prints expanded command with line number
foo is 1
foo is 2
foo is 3 three
+zsh:14> echo ''
help set | grep '^ *-[xv]'
– Soult