bashterminaloutput-redirect

Conditionally directing a command's output to /dev/null in bash


I have following bash script:

flag=false
command_name \
$(  flag == false  && printf %s '>/dev/null') 

I expect no output at Terminal but I still get some. If I redirect output to /dev/null on the same line as command-name without that expansion then it gets suppressed.

Command is dx tool from android SDK

Edit 1: Here the code from script

dx \
    --dex \
    $( ( (( flag_v == 1 )) || (( flag_v == 'd' ))) && printf %s '--verbose') \
    --no-strict \
    --output="../"$app_name.jar \
    $(find . -type f -name '*.class') \
    $( $dexflag == false && printf %s '>/dev/null')

As I run the tool and it works as expected. I do not think that it could be an error stream.


Solution

  • 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:


    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[@]}"