-1

The below piece of script is not behaving as expected

if docker pull docker.pkg.github.com/private-repo/centos7 | grep -q 'Error response from daemon: unauthorized'; then
  echo "matched"
else 
  echo "unmatched"
fi

output

Error response from daemon: unauthorized
unmatched

expected output

matched

I have followed this post

What i have tried: i replaced "docker.pkg.github.com/private-repo/centos7" with echo "Error response from daemon: unauthorized" and it gives expected o/p as matched.

so, what i understand here is the o/p from command "docker pull docker.pkg.github.com/private-repo/centos7" is not captured by "grep" but i don't understand why?

I've also tried this but same result:

docker pull docker.pkg.github.com/private-repo/centos7 | grep 'Error response from daemon: unauthorized' &> /dev/null
if [ $? == 0 ]; then
   echo "matched"
else
   echo "unmatched"
fi

Working solution suggested by @Gordon Davisson

docker pull docker.pkg.github.com/private-repo/centos7 2>&1 | grep 'Error response from daemon: unauthorized' &> /dev/null
if [ $? == 0 ]; then
   echo "matched"
else
   echo "unmatched"
fi

output: matched

  • Does "matched" or "unmatched" appear in your output? – Tyler Liu Jan 16 '23 at 05:51
  • Please add to your question (no comment): What have you searched for, and what did you find? What have you tried, and how did it fail? – Cyrus Jan 16 '23 at 06:09
  • sorry, i corrected the o/p it displays "Error response from daemon: unauthorized and unmatched" – Rajsekar Reddy Jan 16 '23 at 06:09
  • 5
    I'm pretty sure that error message is going to stderr ("standard error"), but only stdout ("standard output") is being piped to `grep`. You need to put `2>&1` before the pipe symbol to redirect both. (Bash also has a `|&` shorthand for redirecting both, but I don't recommend it.) See ["Bash Grep Quiet SSH Output"](https://stackoverflow.com/questions/35496709/bash-grep-quiet-ssh-output) and ["Piping both stdout and stderr in bash"](https://stackoverflow.com/questions/16497317/piping-both-stdout-and-stderr-in-bash). – Gordon Davisson Jan 16 '23 at 06:17
  • See also [How can I pipe `stderr` and not `stdout`?](https://stackoverflow.com/q/2342826/15168) You have to decide what you want to do with the standard output from the `docker` command. You can discard it (easy) or capture it along with the error output, or capture it separately from the error output. – Jonathan Leffler Jan 16 '23 at 06:51

2 Answers2

1

It’s just as @Gordon Davisson said, and please give him the answer credit if he chooses to claim. I’m making the answer more visible.

This is an oversimplification, but it will get the point across. All “outputs” are sent to the terminal through stdout and stderr.

When you use the basic pipe-syntax (|), the only thing actually being processed by the pipe is the stdout. The stderr will still be printed to the terminal. In your case this is undesirable behavior.

The fix is to force the stderr into the stdout BEFORE the pipe, the syntax for this is 2&>1 (or in Bash |&). This works around the pipe’s limitation of only being able to process stdout, and it also prevents the stderr leak into the terminal.

if docker pull… 2&>1 | grep -q…
<SNIPPED>

OR IN BASH

if docker pull… |& grep -q…
<SNIPPED>

The reason your 2nd-attempted solution didn’t work was because pipes and redirections are processed in-order from left-to-right.

if docker pull… | grep… &> /dev/null
#              ^ LEAK HAPPENS HERE, FIX COMES TOO LATE
<SNIPPED>

Meaning that the stderr leak into the terminal already occurred BEFORE you redirected grep’s output. And that the error wasn’t occurring from grep.

-1

You might have some luck with just searching for Error instead of the whole string and see if you got something wrong with the way you typed out the string.