Conditionally Redirecting Stdout
Redirections are shell syntax -- they have to be recognized at a parsing phase that comes before parameter expansion, so you can't generate them via variable expansion (without committing evil).
What you can do (in bash 4.1 or later) is have an unconditional redirection, but have the thing it redirects to change:
# Create an out_fd variable that points to stdout (FD 1) if dexflag != "false", or to a new
# handle on /dev/null otherwise
if [[ $dexflag = false ]]; then
exec {out_fd}>/dev/null # maybe put 2>&1 as well to suppress stderr
else
out_fd=1 # use FD 1 (stdout)
fi
# run dex with its stdout redirected to the FD number in "out_fd"
dex ... >&"$out_fd"
# if out_fd is not stdin/stdout/stderr, then go ahead and close it when done.
(( out_fd > 2 )) && exec {out_fd}>&-
Note:
- A string comparison is done in the form
[[ $var = $pattern ]]
(or [[ $var = "$string" ]]
to do an exact match). See the bash-hackers' wiki on the conditional expression.
- In bash 4.1 or later,
exec {fd_varname}>file
opens file
, and puts the file descriptor number pointing to that file in the variable fd_varname
. exec {fd_varname}>&-
closes the file descriptor whose number is stored in fd_varname
.
- With older versions of bash, you can still do this logic, but instead of having a file descriptor number automatically assigned, you'll need to do so by hand, manually assigning an otherwise-unused FD number that isn't any of 0, 1 or 2 (which are reserved for stdin, stdout and stderr). Thus, in that case, it might be
exec 3>/dev/null
or exec 3>&1
in the if
branches, >&3
on the dex
command, and exec 3>&-
to close it.
Safely Generating Argument Lists Conditionally
See BashFAQ #50 for a long discussion. In short, though: For everything but the redirection to /dev/null
, there's one simple change needed to bring this in line with best practices: Use an array.
#!/bin/bash
args=( )
case $flag_v in
1|d) args+=( --verbose ) ;;
esac
while IFS= read -r -d '' filename; do
args+=( "$filename" )
done < <(find . -type f -name '*.class' -print0)
dx --dex --no-strict --output="../$app_name.jar" "${args[@]}"
- See BashPitfalls #1 describing why
$(find ...)
(like $(ls ...)
) is unsafe, and Using Find going into best practices.
- See BashFAQ #24 to understand why
while read ...; do ...; done < <(find ...)
is used instead of find ... | while read ...; do ...; done
.