CommaToast
CommaToast

Reputation: 12238

Why does cat exit a shell script, but only when it's fed by a pipe?

Why does cat exit a shell script, but only when it's fed by a pipe?

Case in point, take this shell script called "foobar.sh":

#! /bin/sh
echo $#
echo $@
cat $1
sed -e 's|foo|bar|g' $1

And a text file called "foo.txt" which contains only one line:

foo

Now if I type ./foobar.sh foo.txt on the command line, then I'll get this expected output:

1
foo.txt
foo
bar

However if I type cat foo.txt | ./foobar.sh then surprisingly I only get this output:

0

foo

I don't understand. If the number of arguments reported by $# is zero, then how can cat $1 still return foo? And, that being the case, why doesn't sed -e 's|foo|bar|g' $1 return anything since clearly $1 is foo?

This seems an awful lot like a bug, but I'm assuming it's magic instead. Please explain!

UPDATE

Based on the given answer, the following script gives the expected output, assuming a one-line foo.txt:

#! /bin/sh
if [ $# ]
then
yay=$(cat $1)
else
read yay
fi
echo $yay | cat
echo $yay | sed -e 's|foo|bar|g'

Upvotes: 1

Views: 137

Answers (2)

BadZen
BadZen

Reputation: 4274

No, $1 is not "foo". $1 is

ie, undefined/nothing.

Unlike a programming language, variables in the shell are quite dumbly and literally replaced, and the resulting commands textually executed (well, sorta kinda). In this case, "cat $1" becomes just "cat ", which will take input from stdin. That's terribly convenient to your execution since you've kindly provided "foo" on stdin via your pipe!

See what's happening?

sed likewise will read from stdin, but is already on end of stream, so exits.

Upvotes: 3

John Kugelman
John Kugelman

Reputation: 361899

When you don't give an argument to cat, it reads from stdin. When $1 isn't given the cat $1 is the same as a simple cat, which reads the text you piped in (cat foo.txt).

Then the sed command runs, and same as cat, it reads from stdin because it has no filename argument. cat has already consumed all of stdin. There's nothing left to read, so sed quits without printing anything.

Upvotes: 2

Related Questions