begin  quoting Ralph Shumaker as of Sat, Mar 29, 2008 at 06:10:40PM -0700:
> SJS wrote:
> >begin  quoting Ralph Shumaker as of Sat, Mar 29, 2008 at 09:55:37AM -0700:
> >[snip]
[chop]
> >>Could someone please show me, as simply as possible, an example script 
> >>or program that uses each of these?  I don't know enough about it to 
> >>envision it.
> >>    
> >
> >-----------------------------------------------------------------------------
> >#!/bin/psuedoscript
> >#
> ># Find all of the files with copyright notices
> >
> >foreach f in $( find . -type f -iname '*.jpg' ) do
> >   print -stdstatus "Processing file $f"
> >   if ( ! -r $f ) then
> >      print -stderr "Cannot read file $f"
> >   fi
> >   readjpgcmt $f | grep -i "copyright"
> >   if ( $status ) then
> >      print -stdout "$f"
> >   fi
> >rof
> >
> >-----------------------------------------------------------------------------
> 
> 
> I actually felt excitement when I saw the code, thinking, "I may finally 
> understand this well enough to retain it.".

Not bad for a made-up (i.e., fake) scripting language, eh?

> The only thing I don't see in your example is an explicit "stdin".  Is 
> that one ever used explicitly, like you just did above with the other three?

Hm. Lemme think on that. I'm sure there are ways...

> In the example above, what things I did not know, I was able to figure 
> out from the context of the rest (for example, the "! -r $f" was unclear 
> to me until the next line of code).

Yah. I should have taken the time to actually compose the entire
example in bourne shell or something, but that would have required
real work, and I was feeling lazy.

> >>And just for grins, let's say the author wants more output channels for 
> >>whatever reason.  Would he likely choose higher numbers than the next 
> >>available numbers (just in case POSIX later decides to add more 
> >>stdxxx)?  Or would he likely use the next numbers available since stdin, 
> >>stdout, and stderr have been the only ones for many many many years?
> >>    
> >
> >Bourne shell apparently allows this.
> >
> >Consider:
> >-----------------------------------------------------------------------------
> >$ cat fdtest.c
> >
> >#include <stdlib.h>
> >#include <stdio.h>
> >
> >int main( int argc, char **argv ) {
> >   FILE *stdstatus;
> >
> >   fprintf( stdout, "stdout\n");
> >   fprintf( stderr, "stderror\n");
> >
> >   stdstatus = fdopen( 3, "w" );
> >   if ( stdstatus == NULL ) {
> >      if ( argc > 1 ) fprintf( stderr, "Can't open file descriptor
> >#3\n");
> >      return EXIT_FAILURE;
> >   }
> >
> >   fprintf( stdstatus, "stdstatus\n");
> >
> >   return EXIT_SUCCESS;
> >}
> >$
> >-----------------------------------------------------------------------------
> 
> 
> I'm guessing this "fdtest.c" is a made-up example?  (I don't find it in 
> my fc7.)  If so, are you saying that an individual can assign his own 
> choice of terms to open channels?  Is that what you did above for channel 3?
>
> The code looks like C (tho I am unfamiliar enough with other languages 
> to be able to distinguish it) and the ".c" seems to confirm that.

You see the source code right there. It's a C program of my own devising.

> Just for the sake of helping me to be able to follow better in the code 
> above, please explain the line:
> int main( int argc, char **argv ) {
> I don't know C very well at all.  I think "main( ... )" is the title of 
> the "{ ... }" code that follows (perl taught me that).  I don't know the 
> terms "int", "argc", "char", "**argv", or why the double asterisk 
> precedes "argv".

That's a method declaration. The name of the method is "main". The
method returns something of type int (meaning integer). In C, "main"
is the program entry-point method name.

The main method takes an array of strings. Strings are arrays of chars,
that is, characters. So it's an array of (array of chars); but being
C, you can substitute pointers, and "char **argv" is easier to type
than "char [][] argv", so that's my habit.

> Also, please explain the next line, namely:
> FILE *stdstatus;

It's a declaration of a variable named "stdstatus" of type
pointer-to-FILE. FILE is a library-defined type.

> Why the single asterisk preceding "stdstatus"?  Other than that, I 

It indicates that this is a pointer variable.

> assume that this line is an instruction to create a "file" (all in *nix 
> is a file) called "stdstatus" and that the line(s) following (in the 
> block) describe aspects about what kind of file it is as well as 
> handling the error if not being able to open it the way you expect it to 
> work.  But if that's the case, I don't understand why the following two 
> lines seem to be part of that process:
>
> fprintf( stdout, "stdout\n");
> fprintf( stderr, "stderror\n");

This is a sample program that prints output to stdout and stderr, and,
if possible, to file-descriptor 3.

> Perhaps "FILE *stdstatus" _could_ be placed just prior to the "stdstatus 
> = ..." line, but coding etiquette places it at the beginning of the 
> block?

C99 allows more flexibility when it comes to the placement of variable
defintions, or so I hear (I do need to get a good reference book on C99
before C2020 comes out).  In C89, all variables had to be declared at
the top of a block.

>         And perhaps the "stdstatus = ..." and "if ( ... ) { ... } could 
> be placed right after the "FILE *stdstatus" line, but maybe scalability 
> and readability argue that it should be placed just prior to its debut?

I want to print out something to stdout and stderr regardless of whether
or not anything could be printed to file descriptor #3.

> I think I spelled out most of what I don't understand about the code 
> above.  Oh, one more thing:
> stdstatus = fdopen( 3, "w" )
> I assume fdopen is file-descriptor-open, and 3 being the next available 
> number (after 0=stdin, 1=stdout, and 2=stderror).

Yes, and also because in the examples that followed, I was messing about
with file descriptor #3.

>                                                    I don't get the 
> '"w"'.  "man fdopen" (more confusing than not) explains the 'w' option 
> but it doesn't help me to understand it.  Although, reading the other 
> options help me to understand this one better.  This option is only for 
> writing out, and wipes out any previous content in '3', yes?

Yes.

> I think I understand the rest of it (partly because of the behavior of 
> it in the examples below, and partly for similarities to other languages).

Okay.

> >>Let's say that a user invokes that program.  What will he see?
> >>
> >>Let's say that a user invokes that program with simple redirection to a 
> >>file.  What will he see?
> >>    
> >
> >-----------------------------------------------------------------------------
> >lancre> !gcc
> >gcc -o fdtest fdtest.c
> >  
> 
> 
> You just compiled fdtest.c into fdtest?

Yup.

> 
> >lancre> ./fdtest
> >stdout
> >stderror
> >lancre> ./fdtest -v
> >stdout
> >stderror
> >Can't open file descriptor #3
> >  
> 
> 
> I don't know what is "lancre>" (other than a possible reference to "Ever 
> After"),

Command-prompt.

>          but it appears that the "stdstatus" assignment to 3 failed in 
> that environment?

Correct. When the program ran, there was no viable file-descriptor #3.

> >lancre> sh
> 
> Entering into an "sh" shell (close enough to bash for me to follow).

Ancestor of bash.

> >$ ./fdtest
> >stdout
> >stderror
> >$ ./fdtest -v 3>&1
> >stdout
> >stderror
> >stdstatus
> 
> 
> So if cdparanoia had status messages going to 3 (stdstatus), and 
> defaults to "-v 3>&2", and --quiet changes it such that 3>/dev/null, 
> then Lan will be happy if he uses --quiet?  ;)  Anybody know if 
> cdparanoia puts status messages out directly on channel 2 or just 
> redirects whatever channel it uses for status messages to show up on 2?

My thought was that if cdparanoia *didn't* put its chatty messages
out on a separate channel, that would be a relatively simple change;
at program start it could check to see if fd#3 was open, and if so,
use it, else use stderr, for "default" behavior.

Probably simpler than trying to switch --quiet to default and add a --verbose
option.

> >$ ./fdtest -v 3>&1 1>out.1 2>out.2
> >stdstatus
> >$ cat out.1
> >stdout
> >$ cat out.2
> >stderror
> >$
> >-----------------------------------------------------------------------------
> 
> Amazingly, I actually followed all that.  Thanks.

You're welcome.

[chop]
> >>I've seen fancy ~"> 2&"~ or whatnot (couldn't quote it accurately from 
> >>memory since I never really understood it).  Is there some resource that 
> >>could explain such things, preferably simple explanations designed for 
> >>total NOOBS?
> >>    
> >
> >1, 2, 3, etc. are file descriptors.
> 
> So, in coding, you use the terms stdin, stdout, stderr, and (our 
> proposed POSIX-adopted) stdstatus, but on the command line you use 0, 1, 
> 2, and 3 respectively, yes?

In the bourne shells, yes.

> >#>filename will redirect file descriptor # to the file filename
> >
> >The file &# is special -- that's a target file descriptor, so when
> >you see A>&B (in a bourne shell),  where A and B are numbers, that's
> >saying "point A to wherever B is right now".
> >
> >-----------------------------------------------------------------------------
> >$ ./fdtest > out.1 2>&1
> >$ ./fdtest 2>&1 > out.2
> >stderror
> 
> So each one is successive.  Each one builds upon the previous.

Left-to-right, yup.

> >$ cat out.1
> >stderror
> >stdout
> 
> 
> Why did stderror appear _before_ stdout?  I expected the reverse sequence.

stderr is unbuffered, it writes immediately.

stdout is buffered, it doesn't always write immediately.

...so when stdout and stderr both write to the same file descriptor, it's
easily the case where stderr may beat stdout to the punch.

> >$ cat out.2
> >stdout
> >$
> >-----------------------------------------------------------------------------
> >
> >If you really wanted to, you could swap stdout and stderr...
> >
> >-----------------------------------------------------------------------------
> >$ ./fdtest
> >stdout
> >stderror
> >$ ./fdtest > /dev/null
> >stderror
> >$ ./fdtest 2> /dev/null
> >stdout
> >$ ./fdtest > /dev/null 2>&1
> >$ ./fdtest 3>&1 1>&2 2>&3 > /dev/null
> >stderror
> >stdstatus
> >$
> >-----------------------------------------------------------------------------
> 
> 
> I totally followed it until the last one.  On the last one, I expect the 
> opposite result.  I expect "stderror" and "stdstatus" to end up in 
> /dev/null and "stdout" to be the only one showing up on the screen.  
> What did I miss?
> 
> Here's how I see it (correct me where I go wrong):
> $ ./fdtest 3>&1 (3 jumps out of stdstatus' bed and into bed with 1 in 
> stdout's bed)
> $ ./fdtest 3>&1 1>&2 (1 jumps out of stdout's bed and into bed with 2 in 
> stderr's bed)
> $ ./fdtest 3>&1 1>&2 2>&3 (2 jumps out of stderr's bed and into bed with 
> 3 (currently in stdout's bed - even though 1 is now in stderr's bed)
> $ ./fdtest 3>&1 1>&2 2>&3 > /dev/null (dumps stdout's bed (with current 
> occupants 3 and 2) into /dev/null and outputs stderr's bed (with current 
> occupant 1) to screen)

I don't understand the 'jumping into bed' notation.

Let's start with a more visual representation

   1 --------------------------> stdout

   2 --------------------------> stderr

   3 --------------------------> undefined

When we wrote 3>&1, we changed that to

   1 --------------------------> stdout

   2 --------------------------> stderr

   3 --------------------------> stdout

Then we wrote 1>&2

   1 --------------------------> stderr

   2 --------------------------> stderr

   3 --------------------------> stdout

Then we write 2>&3

   1 --------------------------> stderr

   2 --------------------------> stdout

   3 --------------------------> stdout

Then we wrote > /dev/null

   1 --------------------------> /dev/null

   2 --------------------------> stdout

   3 --------------------------> stdout

-- 
Simpler than it first appears.
Stewart Stremler


-- 
[email protected]
http://www.kernel-panic.org/cgi-bin/mailman/listinfo/kplug-list

Reply via email to