I am writing a Bash script where I want all commands to be echoed as they occur. I know that I need to use set -x
and set +x
to toggle this behaviour off and on, respectively (SOF post here). However, it doesn't echo everything, namely, I/O redirects.
For example, let's say I have this very simple Bash script:
set -x
./command1 > output1
./command2 arg1 arg2 > output2
This will be the output
+ ./command1
+ ./command2 arg1 arg2
Bash is not echoing my stdout redirect to output1 and output2. Why is this? How can I achieve this behaviour? Perhaps is there a shopt
option that I must set in the script?
NOTE: I also noticed that pipes will not print as expected. For example, if I were to use this command:
set -x
./command3 | tee output3
I will get this output:
+ tee output3
+ ./command3
How do I make the commands be echoed exactly in the way they are written instead of having the pipe reordered by the script?
$ echo “Hello” > hello. txt The > command redirects the standard output to a file. Here, “Hello” is entered as the standard input, and is then redirected to the file **… $ cat deserts.
The echo command is used to display a line of text that is passed in as an argument. This is a bash command that is mostly used in shell scripts to output status to the screen or to a file.
In Linux, for redirecting output to a file, utilize the ”>” and ”>>” redirection operators or the top command. Redirection allows you to save or redirect the output of a command in another file on your system. You can use it to save the outputs and use them later for different purposes.
Neither set -x
nor the DEBUG trap will provide full information when certain constructs are used.
Examples are:
ex1.sh
for i in a b c
do
echo $i # Where does the output go?
done > outfile # Here!
ex2.sh
c="this"
case "$c" in
this) echo sure ;; # Where does the output go?
that) echo okay ;;
esac > choice # Here!
ex3.sh
what="up"
while [ "$what" = "up" ]
do
echo "Going down!" # Where does the output go?
what="down"
echo "Newton rulezzz!" > thelaw
done > trying # Here!
and many more like these, let alone all kinds of nested variants. I don't know of an easy way to handle these, except to enter into the land of full Bash script parsing, which is a minefield...
EDIT: If Bash-specific features are not required, and backwards compatibility with the Bourne shell will do, the Korn shell (ksh, tested with version 93u+ 2012-08-01) does a bit better on showing information for redirects:
$ ksh -x ex1.sh
+ 1> outfile
+ echo a
+ echo b
+ echo c
$ ksh -x ex2.sh
+ c=this
+ 1> choice
+ echo sure
$ ksh -x ex3.sh
+ what=up
+ 1> trying
+ [ up '=' up ]
+ echo 'Going down!'
+ what=down
+ echo 'Newton rulezzz!'
+ 1> thelaw
+ [ down '=' up ]
You should rather use set -v
.
-v
Print shell input lines as they are read.
The output seems to meet your expectation.
$ set -v
$ ./command1 > output1
./command1 > output1
sh: ./command1: No such file or directory
$ ./command2 arg1 arg2 > output2
./command2 arg1 arg2 > output2
sh: ./command2: No such file or directory
$ ./command3 | tee output3
./command3 | tee output3
sh: ./command3: No such file or directory
It isn't possible with set -x
. Your only option is to view the current command through a DEBUG
trap.
trap 'printf %s\\n "$BASH_COMMAND" >&2' DEBUG
This won't show the precise arguments as set -x
will. Combining them should give you the full picture, though it's a lot of debug output.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With