vipin%samsun@Sun.COM (Vipin Samar) (11/10/87)
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. ? vipin@sun.com || sun!vipin || (415) 691-6694 (o) || (408) 749-0259 (r)
decot@hpisod2.HP.COM (Dave Decot) (11/11/87)
> 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
chris@mimsy.UUCP (Chris Torek) (11/12/87)
In article <33414@sun.uucp> vipin%samsun@Sun.COM (Vipin Samar) writes: >{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) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
vic@phoenix.Princeton.EDU (V Duchouni) (11/13/87)
In article <9316@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >In article <33414@sun.uucp> vipin%samsun@Sun.COM (Vipin Samar) writes: >>{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. V. Duchovni: email: vic@fine.princeton.edu
gwyn@brl-smoke.ARPA (Doug Gwyn ) (11/13/87)
In article <33414@sun.uucp> vipin%samsun@Sun.COM (Vipin Samar) writes: >{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).
katzung@laidbak.UUCP (Brian Katzung) (11/14/87)
In article <9316@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >In article <33414@sun.uucp> vipin%samsun@Sun.COM (Vipin Samar) writes: ... >>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
kyle@xanth.UUCP (Kyle Jones) (11/15/87)
In article <9316@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes: > In article <33414@sun.uucp> vipin%samsun@Sun.COM (Vipin Samar) writes: > >[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). kyle jones <kyle@odu.edu> old dominion university, norfolk, va usa
milgr%brandeis.csnet@RELAY.CS.NET (Marc Milgram) (11/16/87)
Subject: Re: C-shell idiosyncracy ?? > 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: > {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 milgr@brandeis.edu.cs.net
chris@mimsy.UUCP (Chris Torek) (11/16/87)
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 in <33414@sun.uucp>, however, was `why does this happen'; that was 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) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris