Question

I realize the fact but I don't know why:

cat abc | echo $?

if abc does not exist, but above command still return 0. Anyone knows the theory about why?

Was it helpful?

Solution

The reason why it must be this way is that a pipeline is made of processes running simultaneously. cat's exit code can't possibly be passed to echo as an argument because arguments are set when the command begins running, and echo begins running before cat has finished.

echo doesn't take input from stdin, so echo on the right side of a pipe character is always a mistake.

UPDATE:

Since it is now clear that you are asking about a real problem, not just misunderstanding what you saw, I tried it myself. I get what I think is the correct result (1) from a majority of shells I tried (dash, zsh, pdksh, posh, and bash 4.2.37) but 0 from bash 4.1.10 and ksh (Version JM 93u+ 2012-02-29).

I assume the change in bash's behavior between versions is intentional, and the 4.1.x behavior is considered a bug. You'd probably find it in the changelog if you looked hard enough. Don't know about ksh.

csh and tcsh (with $status in place of $?) also say 0, but I bet nobody cares about that.

People with bigger shell collections are invited to test:

for sh in /bin/sh /bin/ksh /bin/bash /bin/zsh ...insert more shells here...; do
  echo -n "$sh "
  $sh -c 'false;true|echo $?'
done

OTHER TIPS

It does not have anything to do with cat abc, but with the previous command you executed. So the code you get when doing cat abc | echo $? is telling if the previous command in your history was successful or not.

From man bash:

Special Parameters

? - Expands to the exit status of the most recently executed foreground pipeline.

So when you do:

cat abc | echo $?

The echo $? refers to the previous command you used, not cat abc.

Example

$ cat a
hello
$ echo $?
0

$ cat aldsjfaslkdfj
cat: aldsjfaslkdfj: No such file or directory
$ echo $?
1

So

$ cat a
$ cat a | echo $?
0

$ cat aldsjfaslkdfj
cat: aldsjfaslkdfj: No such file or directory
$ cat a | echo $?
1

echo $? will give output of previous command which you have executed before not output of piped command. So, you will always get echo $? as 0 even if command failed before pipe.

You pipe the output from 'cat abc' to 'echo $?' which is not what you want. You want to echo the exit code of 'cat'

cat abc; echo $?

is what you want. Or simply write it in two lines if you can.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top