I have a couple of BASH scripts that launch programs I commonly use with common arguments using variables for the command and arguments. The invocation appears at the end like so:
$PROGRAM $ARG1 $ARG2 &
Now I want to redirect output to stderr and stdout to /dev/null
by default. I want to be able to disable that with a switch to the script (-v
= verbose). But if I try to assign "2>&1 > /dev/null"
to a var, say REDIRECTION
, (clearing it if verbose is specified) and try to invoke like so:
$PROGRAM $ARG1 $ARG2 $REDIRECTION &
The redirection directives are passed as arguments to the program. Is there a way to do this? Or do I have to use my solution which is to have 2 separate invocation lines, one with and one without the redirection directives, depending on "verbosity"?
One option is to use the eval
builtin, which processes its arguments like a Bash command, handling things like redirection operators. However, eval
is pretty risky, since it will reprocess all of its arguments, even ones that have already been processed properly, and this can cause bizarre or unsafe behavior if not done perfectly.
Since the only problematic difference between the two versions of your command is the presence or absence of redirections, a better option is to use the exec
builtin. This command:
exec >/dev/null 2>&1
redirects the STDOUT and STDERR of the remainder of a shell-script to /dev/null
. This command:
[[ "$IS_VERBOSE" ]] || exec >/dev/null 2>&1
will run exec >/dev/null 2>&1
unless $IS_VERBOSE
is non-blank, in which case it does nothing. (You can replace [[ "$IS_VERBOSE" ]]
with whatever sort of conditional expression you're already using to detect verbosity.)
So, what you'd want is something like this:
(
[[ "$IS_VERBOSE" ]] || exec >/dev/null 2>&1
"$PROGRAM" "$ARG1" "$ARG2" &
)
The parentheses ( ... )
are to set up a subshell, so the exec
command (if run) only affects up until the )
.
(By the way, note that I changed your 2>&1 > /dev/null
to > /dev/null 2>&1
: the order matters.)
Rather than trying to encode shell syntax into parameter, just put the default destination for each redirection operator in a parameter, and allow a method for overriding the default.
# A little bash-specific, but appropriate defaults should exist for the shell
# of your choice.
STDOUT=/dev/stdout
STDERR=/dev/stderr
if some-test; then
STDOUT=some-other-file
fi
if some-other-test; then
STDERR=different-file
fi
$PROGRAM $ARG1 $ARG2 > $STDOUT 2> $STDERR
You can build any command line you like and then use eval to execute it:
line="echo hello"
if ....
line="$line > junk.out"
fi
eval $line
(BUt I would probably go with the 2-line approach you suggest as being easier to read and understand...)