davisd@cpsvax.cps.msu.edu (Dug) (02/28/90)
Check this out.... % jobs [1] + Stopped cat % jobs | wc 0 0 0 Why can't "jobs" get piped into "wc" (word count)? I can redirect the output of "jobs" to a file, so why can't I do it to program? Just wondering if someone out-there knew. -Dug
gwyn@smoke.BRL.MIL (Doug Gwyn) (02/28/90)
In article <6662@cps3xx.UUCP> davisd@cpsvax.cps.msu.edu (Dug) writes: >% jobs | wc > 0 0 0 There are no suspended jobs in the shell that's running the pipeline (it's a subprocess of the one that printed the prompt).
davisd@cpsvax.cps.msu.edu (Dug) (03/01/90)
In article <12251@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: #In article <6662@cps3xx.UUCP> davisd@cpsvax.cps.msu.edu (Dug) writes: #>% jobs | wc #> 0 0 0 # #There are no suspended jobs in the shell that's running the pipeline #(it's a subprocess of the one that printed the prompt). But it that's true then why can I redirect it to a file and have my stopped jobs show up there? (i.e. jobs > test will result in "test" having the correct output of jobs) -Dug
dce@smsc.sony.com (David Elliott) (03/01/90)
In article <6669@cps3xx.UUCP> davisd@cpsvax.UUCP (Dug) writes: >In article <12251@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: >#In article <6662@cps3xx.UUCP> davisd@cpsvax.cps.msu.edu (Dug) writes: >#>% jobs | wc >#> 0 0 0 ># >#There are no suspended jobs in the shell that's running the pipeline >#(it's a subprocess of the one that printed the prompt). > >But it that's true then why can I redirect it to a file and have my >stopped jobs show up there? (i.e. jobs > test will result in "test" >having the correct output of jobs) Mainly because it's an easier problem to solve. With redirection of a builtin, all you have to do is to save the current file descriptor state, run the builtin, and then put it back. When you work with pipes, you have to fork new subshells to run each piece. If you take a look at the csh source (sh.h, specifically), you'll find that csh starts out by saving the standard file descriptors so that it can handle redirection for builtins easily. It is interesting to note that some builtins do work with pipes. History, for example, does just what you'd expect with a pipe (in most cases -- on the machine I'm using right now, history | more doesn't work correctly). If you do need to send the output of jobs through a pipe, your best bet is to just use a temp file. In my .cshrc, I have the following alias which allows me to use the output of "jobs -l" to send me to the working directory for any given job: alias jd 'jobs -l >! $home/.jobdir ; eval `jobdir < $home/.jobdir`' The jobdir command is a simple shell script: #!/bin/sh # # jobdir - print a command to cd to the directory where the named job # is executing. The argument can be +, -, or a 1- or 2-digit # number. No argument is the same as '+'. # PATH=/bin:/usr/bin:/usr/ucb # # Global variables # Myname=`basename "$0"` main() { case "$1" in ""|+) dir=`getplus` ;; -) dir=`getminus` ;; [0-9]|[0-9][0-9]) dir=`getnum "$1"` ;; *) echo "echo bad directory" exit ;; esac case "$dir" in "") echo "cd ." ;; *) echo "cd $dir" ;; esac exit 0 } getplus() { sed -n 's/^[^ ]* +.*(wd: \(.*\))$/\1/p' } getminus() { sed -n 's/^[^ ]* -.*(wd: \(.*\))$/\1/p' } getnum() { sed -n 's/^\['"$1"'\].*(wd: \(.*\))$/\1/p' } main ${1+"$@"} exit 0 -- David Elliott dce@smsc.sony.com | ...!{uunet,mips}!sonyusa!dce (408)944-4073 "...it becomes natural, like a third sense." -- Homer Simpson
gwyn@smoke.BRL.MIL (Doug Gwyn) (03/02/90)
In article <6669@cps3xx.UUCP> davisd@cpsvax.UUCP (Dug) writes: -In article <12251@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: -#In article <6662@cps3xx.UUCP> davisd@cpsvax.cps.msu.edu (Dug) writes: -#>% jobs | wc -#> 0 0 0 -#There are no suspended jobs in the shell that's running the pipeline -#(it's a subprocess of the one that printed the prompt). -But it that's true then why can I redirect it to a file and have my -stopped jobs show up there? (i.e. jobs > test will result in "test" -having the correct output of jobs) Because the shell doesn't find it necessary to set up a subshell in that case; it runs the command with I/O redirected then jumps back to the main command-processing loop. The ways that shells decide when to use subprocesses and when to short-cut them are rather complicated..
chris@mimsy.umd.edu (Chris Torek) (03/07/90)
>>In article <6662@cps3xx.UUCP> davisd@cpsvax.cps.msu.edu (Dug) asks why `jobs | wc' produces `0 0 0' while `jobs' by itself produces at least one line of output. >In article <12251@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) provides a terse but correct answer: >>There are no suspended jobs in the shell that's running the pipeline >>(it's a subprocess of the one that printed the prompt). In article <6669@cps3xx.UUCP> davisd@cpsvax.cps.msu.edu (Dug) asks further: >But it that's true then why can I redirect it to a file and have my >stopped jobs show up there? (i.e. jobs > test will result in "test" >having the correct output of jobs) To understand all of this you need to know several things: first, what makes something a `job'; second, how the shell manages jobs; and third, how the shell manages pipes and file redirection. A `job' is a collection of processes (a `pipeline'), all of which must be direct descendents of the process that controls them. For instance, given % sleep 1000 | cat | tr -d X & the C shell is the immediate parent of three processes, one a `sleep 1000', one a `cat', and one a `tr -d X'. These three are arranged in a pipeline via a great deal of shell magic. The shell manages the jobs via signals and the `wait3' (now `wait4') system call, and (initially) through `process groups'. Only the immediate parent of the job can do this, because only the immediate parent of a process can wait for that process (wait3()/wait4()). The shell creates a sub- process with the `fork' system call: after the shell forks, the child is no longer the immediate parent of any jobs that the parent created. (The parent, however, *is* the immediate parent of the child, and thus the child process is added to the list the parent maintains.) Since the child is not the parent of the other processes, it must forget about them. Now, to create the pipeline `a | b', the shell does the following: step 0: call pipe() to create a pipe. step 1: call fork() to create a subprocess. 1.1: in the child, close stdout, make the write end of the pipe stdout, close the read end of the pipe (not needed), and then exec process `a'. child part of shell is now gone (parent can now continue if it used vfork()). [various details about setpgrp() left out here.] 1.2: in the parent, close the write end of the pipe (no longer needed). record the child process ID as part of the new job. step 2: call fork() to create a subprocess. 2.1: in the child, close stdin, make the read end of the pipe stdin, and then exec process `b'. [more details about setpgrp() left out here.] 2.2: in the parent, close the read end of the pipe. record the child process ID as part of the new job. Now suppose that `b' is anything, but `a' is the `jobs' command. In this case, step 1.1 does not do the exec() to run part a, but rather simply prints out its list of jobs. But wait! This code is run by a child process, and a child process is not the direct parent of any jobs the shell is running, so it has already forgotten about them. Hence, it lists no jobs. Well, what if we run `jobs > foo' instead of `jobs | cat'? This time the shell only has to run one command, so instead of forking, it squirrels away its current stdout, opens the output file `foo', does the task at hand (here printing jobs, not fork-and-exec'ing some other program), and then moves stdout back. (In actuality, the shell cheats and never moves the file descriptors at all, except once when it first starts up.) This time the jobs-printing is done by the original shell; it does not forget about any jobs. Now, the shell could be more clever, and not forget its jobs even when it forks, and then `jobs | cat' would do something useful. But the shell is just not that clever. Incidentally, the C shell gets very confused when you pipe into a built-in: % cat | jobs [1] + Running cat | % Reset tty pgrp from 2710 to 1281 % jobs [1] Hangup cat | % cat | echo % Reset tty pgrp from 2711 to 1281 j [1] Hangup cat | % It does not matter what you pipe into or out of, as long as the last thing in the pipeline is a built-in. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris