[net.unix-wizards] sh bug

stevesu@bronze.UUCP (Steve Summit) (09/23/83)

While I'm dredging up these silly old questions, here's another
one:  Has anyone ever fixed this long-standing bug in sh?

        "If << is used to provide standard input to an asynchronous
        process invoked by &, the shell gets mixed up about naming
        the input document.  A garbage file /tmp/sh* is created,
        and the shell complains about not being able to find the
        file by another name."

The first time I read that I thought, "What an obscure bug.  Who'd
want to do that?"  Since then, though, there have been a couple
of occasions when I've wanted to use that very construction.

Given the bizarre way that the shell is written, and the fact that
the bug has been so glaringly reported there in sh(1) for so long
without being fixed, I would guess that it's nearly impossible. 
Has anyone tried?
                                  Steve Summit
                                  textronix!tekmdp!bronze!stevesu

guy@rlgvax.UUCP (Guy Harris) (09/27/83)

1) The description of the shell bug:

        "If << is used to provide standard input to an asynchronous
        process invoked by &, the shell gets mixed up about naming
        the input document.  A garbage file /tmp/sh* is created,
        and the shell complains about not being able to find the
        file by another name."

is incorrect.  The correct version is:

	"If << is used to provide standard input to an asynchronous
	process invoked by &, the parent shell deletes a temporary
	file needed by the child shell executing the command.  A garbage
	file /tmp/sh* is created, and the shell complains about not
	being able to find the temporary file."

2) Yes, I *tried* fixing it, by having the child shell delete the temporary
file.  The trouble is that you can construct a pathological case in which
neither the parent nor the child shell knows the right time to delete the
temporary file.

"Here documents" which are to have shell variable and `` expansion performed
are done with two files.  The shell makes a literal copy of the text of the
here document at the time the command line is parsed.  Each time the command
is to be executed, the shell reads from the literal copy, expanding variables
and ``s, and writes the expanded copy to another file.  Then the command is
run with its standard input redirected to the expanded copy.  Now, take the
command:

while (something)
do
	command <<EOF &
This is a $test.
EOF
done

The child process (i.e., the one that's going to run the command "command") is
the one that makes the expanded copy of the here document.  Since the
command is going to be executed in a loop, however, it can't delete the literal
copy after it does the expansion because it may be needed next time around
the loop.  The parent knows when it's done with the loop; however, it does
not know when the last child process has opened the literal copy, so it can't
delete the literal copy after the last pass through the loop.  After discovering
this I gave up; does anybody see a way out?  The C shell solves the problem
by reading the literal copy directly from the shell file, which is presumably
not deleted by the shell.  I don't remember how it handles the case of when
the loop is typed at the terminal.

Since the same bug is listed in the 5.0 manual, I suspect nobody's come
up with a fix yet; since it has the same statement of the bug, it is
conceivable that nobody in the USG has looked into it.  If anybody's fixed
it, please let us all know; I have to create a lot of trash temporary files
because I want to kick off loops in the background like that.

	Guy Harris
	{seismo,mcnc,we13,brl-bmd,allegra}!rlgvax!guy

ntt@dciem.UUCP (Mark Brader) (09/29/83)

I don't think the shell should accept the example

	while (something)
	do
		command <<EOF &
	This is a $test.
	EOF
	done

given by rlgvax!guy (Guy Harris).  I think & should cut off what the
forked shell sees, so that the above example would be typed as:

	while (something)
	do
		( command <<EOF
	This is a $test.
	EOF
		) &
	done

Never having used a shell where <<...& worked anyway, I don't know whether
the first version is supposed to work.  However, an approximation of the
desired effect can be obtained by now replacing the (...) with sh -c "...".
It's not as good because of having to escape quotation marks and because of
the limit on argument lists, but will work for simple cases.

I also think the precedence of & and ; should not be equal; I think
a;b&c;d& should be interpreted as (a;b)&(c;d)& with the present interpretation
having to be typed as a;(b&);c;(d&), similarly to ; and |.

Mark Brader, NTT Systems Inc., Toronto

guy@rlgvax.UUCP (Guy Harris) (10/01/83)

The example

	while (something)
	do
		command <<EOF &
	This is a $test.
	EOF
	done

was incorrect; it should have read

	while (something)
	do
		command <<EOF
	This is a $test.
	EOF
	done &

This sort of loop is useful if you want to nroff a bunch of documents in
the background, the macro package has one-time actions (so you can't use
one nroff command), and you want to stick a ".po 10" command at the beginning
of each file but you see no point in 1) creating a file "/tmp/po10" or 2)
editing the documents when the next time you run them you'll only have to
take the ".po 10" out again; this is done with

for i in {the_documents}
do
	nroff {options} - $i <<EOF
.po 10
EOF
done {your_favorite_redirection}&

Unfortunately, the V7 Bourne shell, the System III Bourne shell, and the
System V Bourne shell lose on this; you either have to put the ".po 10"
into a file or run the job in the foreground.

	Guy Harris
	{seismo,mcnc,we13,brl-bmd,allegra}!rlgvax!guy