From: Jose Luis on
Hi,

Does the shell create a process to run "tee" command?

Can the code below print "not found"?

<<snip begin>>
#!/usr/bin/ksh

cat | tee foo >/dev/null <<EOF
one
two
three
EOF

if grep "three" foo 2>&1
then print "found"
else print "not found"

<<snip end>>


Thanks in advance,
Jose Luis
From: Stephane CHAZELAS on
2009-11-12, 23:37(-08), Jose Luis:
> Hi,
>
> Does the shell create a process to run "tee" command?
>
> Can the code below print "not found"?
>
> <<snip begin>>
> #!/usr/bin/ksh
>
> cat | tee foo >/dev/null <<EOF
> one
> two
> three
> EOF
>
> if grep "three" foo 2>&1
> then print "found"
> else print "not found"
>
> <<snip end>>
[...]

Note that:

cat | tee foo << X

is not the same as

cat << X | tee foo

in a pipeline, shells are required (by POSIX) to wait for the
rightmost command but not for the others. Some shells including
some implementations/versions of ksh will and some will not.

The cat command is run with its stdin unchanged and its stdout
pointing to a pipe whose other end has been closed (because
tee's input has been redirected to something else).

If cat reads anything from it's stdin, it will be killed by a
SIGPIPE has soon as it writes it to stdout. Otherwise, it will
run until it finds the end of file on its stdin, in background
if the shell doesn't wait for it, or in foreground otherwise. If
it's stdin is a terminal, it may end up being suspended or
killed (or the read failing and thus terminate with an error) if
its process group is put in the background (of the terminal)
later on.

In any case, tee will run with its stdin connected to a
temporary file containing the here document, and its stdout
connected to /dev/null and every shell will wait for its
termination, so unless "foo" is not writable for some reason, or
any other abnormal condition such as the shell not being able to
create the temp file or not finding the tee command, tee will
always write those lines to "foo"

> Does the shell create a process to run "tee" command?

Unless tee is built in the shell, the "tee" command will have to
run in a separate process as the shell running the script of
course. A process can't run too commands at the same time.

--
St�phane
From: Alan Curry on
In article <04eefdf7-ddea-41de-86f5-ffc6f15e31b3(a)37g2000yqm.googlegroups.com>,
Jose Luis <jose.luis.fdez.diaz(a)gmail.com> wrote:
>Hi,
>
>Does the shell create a process to run "tee" command?

Of course.

>
>Can the code below print "not found"?

No. Well, yes, but not for the reason you think.

>
><<snip begin>>
>#!/usr/bin/ksh
>
>cat | tee foo >/dev/null <<EOF
>one
>two
>three
>EOF

First, your redirections are messed up. The <<EOF needs to be on the left
side of the pipe if you want the heredoc to be the stdin of cat. The way you
have it now, tee is reading the heredoc and cat is reading the script's
original stdin (probably your tty).

But let's assume you fixed that.

The command "cat | tee foo" is run with some redirections. The shell creates
2 child processes connected by a pipe (and the heredoc itself is probably
implemented using an additional pipe). The file descriptors are put in the
right places and then one child execs cat while the other execs tee. The
shell then waits until both of them are finished.

It waits until both of them are finished, because that's how the shell
normally does things. One command, then the next. Unless you put it in the
background.

The tee process won't exit until it's done writing all of its output. If it
failed writing to the file (disk full or some such disaster) it will tell you
on stderr. In that case you might get a "not found" below. If you don't like
that, look up "set -e".

After the 2 child processes have exited, the shell moves on to the grep:

>
>if grep "three" foo 2>&1

By this point, the tee process is done and gone. If it didn't successfully
write to foo, it has at least complained on stderr. There's no race here.

>then print "found"
>else print "not found"
>
><<snip end>>

Missing "fi". And I don't get the point of the 2>&1 either.

--
Alan Curry
From: Stephane CHAZELAS on
2009-11-13, 11:24(+00), Alan Curry:
[...]
> The command "cat | tee foo" is run with some redirections. The shell creates
> 2 child processes connected by a pipe

Note that POSIX doesn't mandate the use of pipes for connecting
cat's stdout to tee's stdin, and as I just found out, recent
versions of ksh93 may use unix domain sockets instead (causing
all sorts of problems).

> (and the heredoc itself is probably
> implemented using an additional pipe)

here docs are implemented with temporary files. POSIX
doesn't mandate it, so future shells (like future versions of
ksh93) might change that, causing all sorts of problems again
(for instance for scripts that assume you can lseek on a
here-document)

> The file descriptors are put in the
> right places and then one child execs cat while the other execs tee. The
> shell then waits until both of them are finished.
[...]

Some (like ksh93t+ on debian) will only wait for tee.

--
St�phane
From: Kaz Kylheku on
On 2009-11-13, Jose Luis <jose.luis.fdez.diaz(a)gmail.com> wrote:
> Hi,
>
> Does the shell create a process to run "tee" command?
>
> Can the code below print "not found"?
>
><<snip begin>>
> #!/usr/bin/ksh
>
> cat | tee foo >/dev/null <<EOF
> one
> two
> three
> EOF

Surely, you mean

tee foo >/dev/null <<EOF
one
two
three
EOF

You have a useless-and-wrong-use-of-cat.

To convert it to a useless-use-of-cat, you are looking for this:

cat <<EOF | tee foo >/dev/null
one
two
three
EOF

See the << here-doc redirection actually has to be, like, on the command
which is to get that redirection. If you want the here-doc to go into
cat, then <<EOF has to be in cat's command line.