1

I have a script that uses the currently-popular method of installing some packages of downloading a bash script and piping it into the shell:

curl --silent https://sdk.cloud.google.com | bash

I would like to suppress all output to stdout generated by the above command. I tried the obvious:

curl --silent https://sdk.cloud.google.com | bash > /dev/null

However, the output generated by the commands inside the downloaded script is still echoed to the terminal. Is there some slightly different syntax I need to use here?

Jason R
  • 11,159
  • 6
  • 50
  • 81
  • 1
    `>` just redirects stdout. You also want to redirect stderr, so you want to say `&> /dev/null` or `>/dev/null 2>&1`. – fedorqui May 23 '16 at 14:09
  • I actually would like to keep `stderr` so I can see any errors. The output to `stdout` is pretty chatty though, so I would like to suppress that. Using this method, I still see all of the typical output to `stdout`. – Jason R May 23 '16 at 14:10
  • I am not sure if it's a good idea to suppress stdout. What if the download script asks you for inputs? – P.P May 23 '16 at 14:13
  • @P.P. This script is run as part of a continuous integration job. The installer detects when it isn't connected to a tty and doesn't prompt for inputs in that case, using default values. Those are fine for my case; I'd just like to strip out all of the installation junk from my CI log. – Jason R May 23 '16 at 14:15
  • Are you certain that the output you want to suppress is really written to `stdout`? If redirecting the shell's `stdout` does not silence it, then that seems unlikely. You can check by redirecting `stdout` to one file and `stderr` to a different file to see what goes where. – John Bollinger May 23 '16 at 14:17
  • @JasonR as per the code the script https://github.com/matthewloring/cloud-trace-performance/blob/master/install_google_cloud_sdk.bash#L134 outputs the trace to stderr . So if you want to silence the trace messages you would need to redirect stderr too to /dev/null – keety May 23 '16 at 14:17
  • 1
    @JohnBollinger and @keety are correct; against my incorrect intuition the script does output to `stderr`. Sorry for the noise, folks. – Jason R May 23 '16 at 14:19
  • It may be popular, but it is *not* a good idea. You are running code from an untrusted source before you can verify what it does. (You might trust https://sdk.cloud.google.com, but you aren't verifying that the code you receive is actually *sent* from there before executing; you could be a victim of a man-in-the-middle attack.) – chepner May 23 '16 at 14:56
  • @chepner: I understand. Note that it does use HTTPS for the download (with certificate validation enabled). I'm not saying that's a panacea, but establishing a level of trust greater than that would take a good amount of effort. You could verify hashes of the downloaded file first, but how do you know to trust the hashes? And so on. – Jason R May 23 '16 at 15:01

1 Answers1

0

Reading the discussion, I would recommend some level of validation, especially if this is part of a continuous integration system. The last you need in that scenario is a false positive. I would recommend the use of the script I compiled to let you capture stderr, stdout and return code so you can test for proper completion or log the output for further diagnosis. I have included it below for your reference:

# #!/bin/bash
# 
# based on posts from stackexchange:
# http://stackoverflow.com/a/26827443/171475
# http://stackoverflow.com/a/18086548/171475
# http://stackoverflow.com/a/28796214/171475

function example_function {
    printf 'example output to stdout %d\n' {1..10}
    echo >&2 'example output to stderr'
    return 42
}



##############################
### using the dot operator ###

if [ "${BASH_VERSINFO}" -lt 4 ]; then
    printf '%s\n' "The source version of this script requires Bash v4 or higher."
else

    # stdout & stderr only
    source <({ cmd_err=$({ mapfile -t cmd_out < <(example_function); } 2>&1; declare -p cmd_out >&2); declare   -p cmd_err; } 2>&1)

    printf "\n%s\n" "SOURCE VERSION : STDOUT & STDERR ONLY"
    printf "%s\n" "${cmd_out[@]}"
    printf "%s\n" "${cmd_err}"

    unset cmd_out
    unset cmd_err


    # stdout & stderr only as well as return code:
    source <({ cmd_err=$({ mapfile -t cmd_out< <( \
        example_function \
      ; cmd_rtn=$?; declare -p cmd_rtn >&3); } 3>&2 2>&1; declare -p cmd_out >&2); declare -p cmd_err; } 2>&1)


    printf "\n%s\n" "SOURCE VERSION : STDOUT, STDERR & RETURN CODE"
    printf '%s\n' "${cmd_out[@]}"
    # alternative version
    # declare -p cmd_out 
    printf '%s\n' "${cmd_err}"
    printf '%s\n' "${cmd_rtn}"

    unset cmd_out
    unset cmd_err
    unset cmd_rtn

fi

##############################
######### using exec #########

# stdout & stderr only
eval "$({ cmd_err=$({ cmd_out=$( \
    example_function \
  ); } 2>&1; declare -p cmd_out >&2); declare -p cmd_err; } 2>&1)"

printf "\n%s\n" "EVAL VERSION : STDOUT & STDERR ONLY"
printf '%s\n' "${cmd_out}"
printf '%s\n' "${cmd_err}"
printf '%s\n' "${cmd_rtn}"

unset cmd_out
unset cmd_err

# stdout & stderr only as well as return code:
eval "$({ cmd_err=$({ cmd_out=$( \
    example_function \
  ); cmd_rtn=$?; } 2>&1; declare -p cmd_out cmd_rtn >&2); declare -p cmd_err; } 2>&1)"


printf "\n%s\n" "EVAL VERSION : STDOUT, STDERR & RETURN CODE"
printf '%s\n' "${cmd_out}"
printf '%s\n' "${cmd_err}"
printf '%s\n' "${cmd_rtn}"


unset cmd_out
unset cmd_err
unset cmd_rtn

Applied to your specific scenario, it might look something like:

source <({ cmd_err=$({ mapfile -t cmd_out< <( \
    curl --silent https://sdk.cloud.google.com | bash \
  ; cmd_rtn=$?; declare -p cmd_rtn >&3); } 3>&2 2>&1; declare -p cmd_out >&2); declare -p cmd_err; } 2>&1)

# return code 0 indicates the command executed fully
if [ "${cmd_rtn}" -eq "0" ]; then
    # the command succeeded
    printf 'The command succeeded\n' 

    # might should do some additional checking of the contents of
    # cmd_out or cmd_err for expected results

elsethen
    # the command failed, do some checking
    printf 'The command failed\n'

    # might should do some logging of the output for further reference
    # or fail the integration check
fi

printf '\n%s\n\n' "Example output of STDOUT, STDERR & RETURN CODE"
printf 'STDOUT: %s\n\n' "${cmd_out[@]}"
printf 'STDERR: %s\n\n' "${cmd_err}"
printf 'RETURN CODE: %s\n\n' "${cmd_rtn}"
John Mark Mitchell
  • 4,522
  • 4
  • 28
  • 29