The following command lets me check if a webpage has specific content. It does not output anything unless the content is found.

curl -v --silent https://somedomain.com/somepage.html 2>&1 | grep 'some content'

The problem is, when I add this to a shell script, the output isn't suppressed any more.

TEST1="curl -v --silent https://somedomain.com/somepage.html 2>&1 | grep 'some content'"

if [[ $? != 0 ]]; then
    #do something if exit status of last command not equal to zero

I have the same problem if I try to store the output of the script in a variable (VAL1)

TEST1="curl -v --silent https://somedomain.com/somepage.html 2>&1 | grep 'some content'"
echo "result should be blank or the found grep $VAL1"

Why does 2>&1 work as expected when running the command directly, but when added to a script the output is directed in the command line?


Jeffs hint's in the comments got me going in the right direction. The accepted answer is correct. The work around I did for my script was to move the code I originally tried to assign to a variable to be in a function and use $( ... ). This way everything ran as expected:

# note that -z checks if variable is empty
test1() {
  VAL1=$(curl -v --silent https://somedomain.com/somepage.html 2>&1 | grep 'some content')
  if [[ -z $VAL1 ]]; then

echo $VAL1
  • pls show current output and expected output Sep 27, 2018 at 14:46
  • It’s an interesting distinction, to me, given that redirection comes after parameter expansion in the sequence of operations.
    – Jeff Schaller
    Sep 27, 2018 at 14:52
  • Notice what happens under set -x: curl ... '2>&1' ... with the single-quotes around the redirection.
    – Jeff Schaller
    Sep 27, 2018 at 14:54
  • 2
    Relating: unix.stackexchange.com/a/269259/117549
    – Jeff Schaller
    Sep 27, 2018 at 14:56

2 Answers 2


Jeff Schaller's comment link is on the nose. The key message from the bash manual (https://www.gnu.org/software/bash/manual/bashref.html#Simple-Command-Expansion)

When a simple command is executed, the shell performs the following expansions, assignments, and redirections, from left to right.

  1. The words that the parser has marked as variable assignments (those preceding the command name) and redirections are saved for later processing.
  2. The words that are not variable assignments or redirections are expanded (see Shell Expansions). If any words remain after expansion, the first word is taken to be the name of the command and the remaining words are the arguments.
  3. Redirections are performed as described above (see Redirections).
  4. The text after the ‘=’ in each variable assignment undergoes tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal before being assigned to the variable.

Step 1 identifies the redirections and saves them.
Step 2 is where variable expansion happens.

The shell sees no redirections in step 1.

Also relevant: I'm trying to put a command in a variable, but the complex cases always fail!


The bad solution is to force a double evaluation :

eval "$TEST1"

The good solution is to split the command semantically (url, content) :

curl -v --silent "$url" |& grep "$content"

Note : |& is syntactic sugar for 2>&1 |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy