which logical device = standard output?
Posted in 2001
Topics: General Discussion
Is there a UNIX logical device which is equivalent to standard output? I have a function takes the output file path as argument and produce a report output to that file. What I want to achieve is that if the caller want the report output to standard output it just pass that "logical device" which is equivalent to the standard output. I know /dev/tty is always current terminal but it is probably not equivalent to STDOUT. Regards, Carl Wu
It is unless the user has redirected stdout. Art s. Kagel Carl Wu wrote: > > Is there a UNIX logical device which is equivalent to standard output? > I have a function takes the output file path as argument and produce a > report output to that file. What I want to achieve is that if the caller > want the report output to standard output it just pass that "logical device" > which is equivalent to the standard output. I know /dev/tty is always > current terminal but it is probably not equivalent to STDOUT. > > Regards, > Carl Wu
Carl Wu wrote in message <3a81d3e8$0$16411$7f31c96c@news01.syd.optusnet.com.au>... >Is there a UNIX logical device which is equivalent to standard output? >I have a function takes the output file path as argument and produce a >report output to that file. What I want to achieve is that if the caller >want the report output to standard output it just pass that "logical >device" which is equivalent to the standard output. I know /dev/tty is >always current terminal but it is probably not equivalent to STDOUT. > I'll give you a possible solution at the end, but I thought I'd explain to you all the important stuff about /dev/tty and STDOUT so you can answer your own question. Skip to the end if you don't care! I won't be offended... really. Some people would say I just talk too much. This is a very UNIX'y question. Take a deep breath: Any process in UNIX may be associated with a "controlling terminal" and generally that terminal is recorded in secret data space of UNIX for the process. You can see it when you run ps. If a process shows up on ps with ? in the tty column, then it has either detached itself or it may have been started from the init process or some other detached daemon which does not assign a controlling terminal to it. The /dev/tty device is a bit of a fake. It looks at the process table in UNIX and (re)opens whatever device happens to be the specified controlling terminal for the process. /dev/tty will fail if there is no controlling terminal for the process. /dev/tty does NOT attach to the STDOUT or STDIN or STDERR for that matter. Also, it will not replace those streams unless your program specifically closes the originals and opens /dev/tty into one of them. A program can close any of the STDx and replace them with any file it chooses, so there is still nothing magical about /dev/tty except for it hooking into the controlling terminal of the requesting process. Sometimes I use /dev/tty deep inside some hard-core shell scripts (or Perl scripts for that matter) when I want to see what's going on but the scripts are already doing extreme violence to the STDIN, STDOUT and STDERR streams. More on that later when you understand those streams properly. Now, about STDIN, STDOUT, and STDERR (another deep breath, please): UNIX originally was built on a concept of a command line, with the ability to pipe the output from one command into another. Forget about programs like vi and 4GL which appear to drive the terminal in a different manner. They are merely sending special codes to the terminal which give the effect of a full-screen interaction. The authors of UNIX also wanted devices and files to be very similar in their usage - they didn't want different system calls depending on whether it's talking to a file, a printer, a screen or a communications line (shh - don't mention ioctl) Because of the UNIX model with pipelined programs and a common model for devices and files, they decided on a concept of a STDIN and STDOUT, so that any program can be made to feed into or from any other program. Normally your shell has those connected to your terminal, and the shell passes them on to any program you run. If you run a pipeline: A | B then the shell will set A's STDOUT to be a pipe, and B's STDIN to be the other end of the same pipe, and the programs can happily do their job. This leads onto the need for STDERR - what if program A wants to report an error? It can't use STDOUT because B will get it instead of the user! So the shell also has STDERR connected to the terminal, and normally it won't get redirected for the A and B programs, unless you start coding things like 2> in your shell scripts. Now, the user can still see error messages from A if program A is courteous enough to send it's error messages there. If you are writing a shell script, you can write your own error message with: echo >&2 "she canna tekk it cappen!" # for the Star Trek fans The >&2 is ugly shell syntax for moving file streams around. Specifically, it makes the output of echo be connected to file 2 (number of the stream we call STDERR). Some people put the >&2 at the end of the line but it doesn't matter where it's written. In Perl, you merely write print STDERR "error message" or use the warn command, which defaults to STDERR. If the STDOUT of a process happens to be pointing to the controlling terminal, then you may think that /dev/tty has hooked into the STDOUT, but it's purely a coincidence, and there are actually subtle differences and effects that you can see which show that they are not really connected to each other, and are not cooperating or coordinating their outputs. Scrambled lines is often a symptom of independent streams to the same device or file, although typically most programs tend to switch to a weaker buffering mode if they detect that they are talking to a physical device - to reduce the scrambled output. Promised programming solution: The biggest problem here is, I don't know what language you are using. Because you write STDOUT I could guess that you are writing Perl because that's the language of perl. C calls them stdout, stdin, and stderr. In Perl, opening a file called "-" is sufficient to hook into the standard streams. Try: open MYFILE, "-" so that MYFILE reads from the STDIN, and since you want to write to whatever the STDOUT is, you could write open MYFILE, ">-" so all you need to do is tell your users about it, and maybe ensure that your code is Doing The Right Thing. If you are writing 4GL, well, 4GL has no real facilities to mess around with this, but if you are using a report then it's very easy to start the report with a chosen target anyway. Here's what we have done: case when outfile = "screen" start report X to pipe "more" when outfile[1] = "|" let outfile[1] = " " start report X to pipe outfile when outfile = "stdout" start report X when outfile = "printer" start report X to printer otherwise start report X to outfile end case That's all the traditional targets covered. Version 7.30 4GL adds a whole rash of new possibilities which you can exploit at your leisure. If you are writing some other language, you'll have to help yourself but I hope I've given you enough information to find out how to do it there. Cheers