C-shell idiosyncracy ??

C-shell idiosyncracy ??

Post by Vipin Sam » Fri, 02 Nov 1990 20:43:00



It seems that I can redirect the output of a C-shell command
to a file, but I cannot pipe it to some other command. Logically,
this should not have happened. Anyway, the following happens
for C-shell as well as for korn-shell.

{samsun} jobs
[1]  + Stopped          emacs foo
{samsun} jobs > bar
{samsun} cat bar
[1]  + Stopped          emacs foo
{samsun} jobs | more
{samsun}

So, for some reasons I just cannot pipe the output of "jobs".
I am just wondering how was this bug (feature !) implemented. ?


 
 
 

C-shell idiosyncracy ??

Post by Dave Dec » Fri, 02 Nov 1990 22:45:00


Quote:> It seems that I can redirect the output of a C-shell command
> to a file, but I cannot pipe it to some other command. Logically,
> this should not have happened. Anyway, the following happens
> for C-shell as well as for korn-shell.

> {samsun} jobs
> [1]  + Stopped             emacs foo
> {samsun} jobs > bar
> {samsun} cat bar
> [1]  + Stopped             emacs foo
> {samsun} jobs | more
> {samsun}

> So, for some reasons I just cannot pipe the output of "jobs".
> I am just wondering how was this bug (feature !) implemented. ?

This works in HP-UX's /bin/csh and in its /bin/ksh, i.e.,
"jobs | more" prints:

    [1]  + Stopped              emacs foo

Dave Decot
hpda!decot

 
 
 

C-shell idiosyncracy ??

Post by Chris Tor » Fri, 02 Nov 1990 03:38:00



>{samsun} jobs
>[1]  + Stopped              emacs foo
>{samsun} jobs > bar
>{samsun} cat bar
>[1]  + Stopped              emacs foo
>{samsun} jobs | more
>{samsun}

>So, for some reasons I just cannot pipe the output of "jobs".

To see why this happens, consider how pipes are implemented.
After creating a pipe, it is necessary to fork.  A fork is
not the parent of any of its parent's processes, hence a
forked sub-C-shell must forget all its parent's jobs.

Hence, `jobs | cat' or `(jobs)' or anything similar produces
no output.  `alias | cat' works fine since a subshell need not
forget about the parent's aliases.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)

 
 
 

C-shell idiosyncracy ??

Post by V Duchou » Fri, 02 Nov 1990 02:14:00




>>{samsun} jobs
>>[1]  + Stopped          emacs foo
>>{samsun} jobs > bar
>>{samsun} cat bar
>>[1]  + Stopped          emacs foo
>>{samsun} jobs | more
>>{samsun}

>>So, for some reasons I just cannot pipe the output of "jobs".

>To see why this happens, consider how pipes are implemented.
>After creating a pipe, it is necessary to fork.  A fork is
>not the parent of any of its parent's processes, hence a
>forked sub-C-shell must forget all its parent's jobs.

     Well, it is not strictly necessary (but very advisable) to fork,
     that is for the command:

machine% built_in | binary

   one migh hope that the shell would fork only once, spawning
   "binary" and execute built_in followed by a wait() , with output to the pipe,
   (potentially stopping if the pipe fills up, ouch!!! One would
   find the shell dead on every instance of a wrong or buggy filter ) in this
   case "jobs | cat" would work.

   Instead the shell also (v?)forks (as it would for "binary1 | binary2")
   and the child (csh) ( which gets a copy of all internal variables,
   hence "alias | cat" as above) executes the built in and exits,
   while the parent waits for the exit of "binary". Here if
   binary is stupid and refuses to read, you will get impatient
   type ^C, and bingo "binary" dies, and the parent takes control.

   It looks like the shell needs some help from the kernel in
   determining the number of current jobs that are still alive
   ( remember if you typed jobs, and the shell was running
   it cannot have been waiting for its children and they may have
   died in the interim ), so while the shell knows the pids and
   job numbers of its children ( and hence so does the child executing
   "jobs" in "jobs | cat" ) the child seeks current info on the jobs
   IT has spawned and finds none!

   This is perhaps disappointing, but it avoids disaster.


 
 
 

C-shell idiosyncracy ??

Post by Doug Gwy » Fri, 02 Nov 1990 08:47:00



>{samsun} jobs
>[1]  + Stopped              emacs foo
>{samsun} jobs | more
>{samsun}

"jobs | more" is a pipeline, so it is run as a subprocess,
and in the subprocess there are no stopped jobs (they belong
to the parent shell process).
 
 
 

C-shell idiosyncracy ??

Post by Brian Katzu » Fri, 02 Nov 1990 01:35:00




...
>>So, for some reasons I just cannot pipe the output of "jobs".
>To see why this happens, consider how pipes are implemented.
>After creating a pipe, it is necessary to fork.

It is necessary to fork to create the read end of the pipe, but
not for the write end of the pipe (and the write end of the pipe
is the supplier of jobs information).  It is just as easy to
write to the file descriptor for a pipe as it is to write to
the file descriptor for a file.  His shell and the several I just
tested are broken because they chose to take the lazy approach by
forking instead of juggling file descriptors in the current shell.
IT CAN BE DONE RIGHT, and from the responses, I gather the HPUX
people did do it right.

Actually, in a degenerate case, you could pipe from one built-in
to another, as long as you didn't ever send more than 4K before
you read it (ie, "history -hr 8 | source -h" would append your
last 8 events in reverse order onto your history list if source
accepted input from the standard input).
-- Brian Katzung   ihnp4!laidbak!katzung

 
 
 

C-shell idiosyncracy ??

Post by Kyle Jon » Fri, 02 Nov 1990 14:04:00




> >[1]  + Stopped         emacs foo
> >{samsun} jobs | more
> >{samsun}

> >So, for some reasons I just cannot pipe the output of "jobs".

> To see why this happens, consider how pipes are implemented.
> After creating a pipe, it is necessary to fork.  A fork is
> not the parent of any of its parent's processes, hence a
> forked sub-C-shell must forget all its parent's jobs.

No, it means the forked child C-shell cannot wait() for them.  The
internal information that csh stores about process states is available
to the child, so why couldn't this information be used?  It would be
wrong in some instances (e.g. a process exits in the meantime) but the
parent C-shell will notice and print updated information at the next
prompt (or immediately if notify is set).


 
 
 

C-shell idiosyncracy ??

Post by Marc Milgr » Fri, 02 Nov 1990 05:23:00


Subject: Re: C-shell idiosyncracy ??

Quote:> It seems that I can redirect the output of a C-shell command
> to a file, but I cannot pipe it to some other command. Logically,
> this should not have happened. Anyway, the following happens
> for C-shell as well as for korn-shell.

> {samsun} jobs
> [1]  + Stopped             emacs foo
> {samsun} jobs > bar

In this case, csh redirects its own output, then finds what jobs it is
running.

But:

Quote:> {samsun} cat bar
> [1]  + Stopped             emacs foo
> {samsun} jobs | more
> {samsun}

In this case, csh finds there is a pipe (|) in the command, so it
spawns off a csh which finds that it is not running any subprocessies.

        -Marc Milgram

 
 
 

C-shell idiosyncracy ??

Post by Chris Tor » Fri, 02 Nov 1990 07:52:00


As several people have pointed out, it is possible (not necessarily
easy) to have builtin commands run as the source or sink of a
pipeline (although at most one such source or sink).  The question

what I answered.

Actually, to be even more specific, csh forks the head ends of all
pipes.  The tail end of a pipe will be done directly by csh if the
command is a csh builtin.  Contrast this with sh, which forks the
tail ends of pipes first:

        a | b | c | d | e &

In csh, you might get

        % jobs
        [1]     714 Runnning            a |
                715                     b |
                716                     c |
                717                     d |
                718                     e

In sh, had it a jobs command, these might be listed as

        718 Running     a |
        717             b |
        716             c |
        715             d |
        714             e

In particular, in csh, builtins are run directly by the shell when
they are at the tail end of pipes.  This is the most straightforward
implementation, given the direction of creation shown above.  Try,
for instance,

        % jobs | cat

and

        % cat /dev/null | jobs

The former produces no output; the latter lists some jobs, then
prints

        Reset tty pgrp from xxx to yyy

---which just goes to show that there are bugs in csh (what a
revelation :-) !).  Indeed, it is necessary to do another `jobs'
command to flush the `cat | jobs' job from csh's joblist.  Also
incidentally, this particular bug would wreak havoc with tty signals
(interrupt, stop) if any of csh's builtins were long-running.

Were csh more clever, it could indeed either avoid forking the jobs
command in `jobs | more' (but at least one `jobs' in `jobs | jobs |
more' must be forked), or defer forgetting about its parent's jobs.
Csh is just not that clever.

Having once again demonstrated that I can write more exposition
on a smaller subject than anyone else :-), I now return you to
your regular netnews,
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)