I was writing a simple script that checks the output of a command that if it displays a certain keyword. To see if it works, I was checking the command from the bash command line.

   $ ls | grep -q foo
   $ echo $?

It displayed 1 or 0 depends on the command output and a grep parameter as I expected.

I get little lazy to type the command again, so I added | echo $? at the end of the command line.

    $ ls | grep -q foo | echo $?

Then regardless the command output, it always returns 0, even if the first part returns 1.

I guess this is normal behavior but I'd like to know why bash works this way.


This is because the pipe takes the stdout and pipes it to the next command, what you want instead is the semicolon.

ls | grep -q foo; echo $?

This finished the ls and grep commands and then executes the echo command.


The special variable $? expands to the exit status of the most recently executed foreground pipeline. In your example, the | echo $? is the most recently executed foreground pipeline, at that point the exit status of the command before the last | is no longer accessible via $?.

On a related note, you can use the exit code directly in conditional statements, for example:

if ls | grep -q foo; then echo success, there is foo; fi

Or, if you want to execute something on success, you could chain the next command using &&:

ls | grep -q foo && echo success

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.