Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash set -x echo redirects as well as commands

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?

like image 878
ecbrodie Avatar asked Mar 12 '13 16:03

ecbrodie


People also ask

How do I redirect echo output to a file in shell 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.

What is echo $$ in bash?

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.

How do you redirect the output of a command to a file in Linux?

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.


3 Answers

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 ]
like image 198
ack Avatar answered Oct 04 '22 07:10

ack


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
like image 35
Melebius Avatar answered Oct 04 '22 06:10

Melebius


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.

like image 22
ormaaj Avatar answered Oct 04 '22 07:10

ormaaj