Shell file Descripters Using named pipes mknod /tmp/pipe$$ p echo "A plumbers job is never done" >/tmp/pipe$$ & cat /tmp/pipe$$ rm -f /tmp/pipe$$ Bash allows this to be a little more direct cat <( echo "A plumbers job is never done" ) In this case the cat was given an actual filename. Reading Files In the csh, all you've got is $<, which reads a line from your tty. What if you've redirected? Tough noogies, you still get your tty. Read in the Bourne shell allows you to read from stdin, which catches redirection. It also means that you can do things like this: exec 3&-, which isn't the same as redirecting it to /dev/null. More Elaborate Combinations Maybe you want to pipe stderr to a command and leave stdout alone. Not too hard an idea, right? You can't do this in the csh as I mentioned in 1a. In a Bourne shell, you can do things like this: exec 3>&1; grep yyy xxx 2>&1 1>&3 3>&- | sed s/file/foobar/ 1>&2 3>&- grep: xxx: No such foobar or directory Normal output would be unaffected. The closes there were in case something really cared about all it's FDs. We send stderr to the sed, and then put it back out 2. NOTE: complex file descriptor handling are often just not needed, simpler use of named pipes and bacgounded commands may often be used in the example situation. For a practical example see "interactive.shell" where a shell script does "expect" like interaction with a telnet session. --------------------------------------------------------------------------- Anthony's General Example Munging the output of 3 (or more) channels of data is a difficult task. The third channel is used to pass the status of the comand before the echo ($#) for error checking. This is vital as the status of the first command in a pipe is normally unavailable (status of a pipe is that of the last command!) ASIDE: Bash lets you get the status of ALL pipeline commands with $PIPESTATUS array. Note the use of sub-shells so that the output stream (example fd 3) is taken from the sub-shell where it is defined and NOT from the previous command. exec 9>&1 # set fd 9 to be the normal (at this time) stdout of program (( ( echo OUTPUT; echo ERROR >&2; echo STATUS >&3 ) \ | sed 's/^/out:/' >&9 ) 2>&1 | sed 's/^/err:/' >&9 ) 3>&1 | sed 's/^/stat:/' >&9 exec 9>&- # close fd 9 results in the following output to fd 9 (the normal stdout) out:OUTPUT err:ERROR stat:STATUS Dan Bernstein --- brnstnd@nyu.edu exec 9>&1; ( exec 2>&1; ls /tmp /foo | sed 's/^/out: /' >&9 ) \ | sed 's/^/err: /' Anthony's Pratical example I had a pipe in which the first command may or maynot exist on the system and if it did exist its location was unknown (non-standard unix command). If it was not present I wanted to do something else. Solution get its status and redirect stderr to device null. The command before this conversion was zoo xp $Zoo $mesgname | tail -n+6 and afterward status=`( ( zoo xp $Zoo $name; echo $? >&3 ) | tail -n+6 >&9 ) 9>&1 2>/dev/null` if [ $status -ne 0 ]; then .... fi Of course it is simplier to just do a "type" test on the command to see see if it is present or not (See script.hints "Is COMMAND available" ) But this works for the unexpected to. Also not that saving output to a temporary may also be simpler, unless the command takes a very very long time, and you want to display wher you have recieved so far. Complex stdout and stderr example (original): Here's something I had to do where I ran dd's stderr into a grep -v pipe to get rid of the statistics dd produces, but had to return the dd's exit status, not the grep's: device=/dev/rmt8 dd_noise='^[0-9]+\+[0-9]+ records (in|out)$' exec 3>&1 status=`((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) | egrep -v "$dd_noise" 1>&2 3>&- 4>&-) 4>&1` exit $status; This is one example where a named pipe and a backgrounded egrep may have been more practical, and simpler to understand.