[clug] Next in my series of "how to do things in /bin/sh that you probably shouldn't".
steve jenkin
sjenkin at canb.auug.org.au
Wed Aug 19 21:39:39 MDT 2009
Andrew Janke wrote on 20/8/09 10:39 AM:
> Suppose that I want to send all output from a shell script to a
> logfile as well as displaying it (within the script). To simply send
> everything in a shell script I can just do this somewhere near the top
> of the script:
>
> exec > logfile.txt 2>&1
>
> But I am greedy, as such it is a pity you can't just do this:
>
> exec | tee logfile 2>&1
>
> So instead the only way I know of doing this is as such:
<snip> Example using a named pipe.
> Seems like an awful amount of work for a simple thing, anyone know a
> better way? Answers of "use python/perl/<some other language>" will
> be dutifully ignored.
>
> Thanks
>
>
> --
> Andrew Janke
> (a.janke at gmail.com || http://a.janke.googlepages.com/)
> Canberra->Australia +61 (402) 700 883
Andrew,
Great question. Thanks for that.
I've spent a little time playing with this - it seems like a nice thing
to do - and think I've spotted the root cause, which points to the
answer(s).
It's to do with shell creating 'pipes' and fiddling per-process file
descriptors.
When you run:
cmd1 | cmd 2
shell does this work for you:
-----
for '|': call pipe() and save pipe_fd[0] and pipe_fd[1]
cmd1: leave fd[0] & fd[2] alone.
close fd[1], dup pipe_fd[1] to fd[1]
now fork & exec 'cmd1'
cmd2: leave fd[1] & fd[2] alone.
close fd[0], dup pipe_fd[0] to fd[0]
now fork & exec 'cmd2'
Wait for completion of both processes...
Return in "$?" the status of cmd2, ignore cmd1's ret-code.
[I could've reversed the sense of the fd[]'s from pipe()]
-----
IIRC, /bin/sh, spawns processes Right to Left, just an added wrinkle.
The essence of the problem is creating the pipe() and associated array
of fd[]'s.
There are some very smart people on this list (you know who you are) who
know much shell trickery. Perhaps they know of a way to capture a 'pipe'
and the file-descriptors at each end of it.
As in, create two processes with a pipe between them & capture the
fd[]'s, then reuse when the processes have exited.
Seems hard because of the local context of each process and passing
fd[]'s back.
I've never investigated 'csh' and descendants in detail - it may have
facilities to allow pipe & fd fiddling.
OR, doing it simply in 'standard shell' is possible only in two ways:
- create a named pipe and manipulate fd's & child processes (your soln)
- use a wrapper to get shell to automagically do the work.
AND, I could be completely wrong headed and Missed The Bleeding Obvious.
Happened before, will happen again :-)
Now, if the semantics of pipes and sockets were more similar, this might
be a little different.
Remember how Tridge solved the 'shell as IP daemon' problem by *writing*
to the socket given as stdin?
Took me by surprise & impressed the hell out me :-)
Looking forward to the continued conversation on this.
HTH
s
--
Steve Jenkin, Info Tech, Systems and Design Specialist.
0412 786 915 (+61 412 786 915)
PO Box 48, Kippax ACT 2615, AUSTRALIA
sjenkin at canb.auug.org.au http://members.tip.net.au/~sjenkin
More information about the linux
mailing list