[GRASS-dev] Merging stdout and stderr

The GRASS console thing (I guess that's where the name gronsole comes from?) which runs commands via the Tcl/Tk "open" command and captures their stdout and stderr, displaying some output as-is to the gronsole window and catching certain things like percentage complete and warnings and displaying them differently is actually quite cool.

I remember discussion on the list about how stdout and stderr had to be merged because Tcl/Tk has a bug/feature in that it treats anything written to stderr as an error indicator for the called program. On Unix this merging is done as follows:
set cmd [concat | $cmd 2>@ stdout]
but the "2>@ stdout" syntax will not work on Windows. A cross-platform solution would be to use the "|&" redirector instead of "2>@". "|&" means "pipe both stdout and stderr to stdin of the following command" (see http://www.tcl.tk/man/tcl8.5/tutorial/Tcl26.html ). This command could then copy everything to its stdout and that's what gronsole gets back.

The Unix cat command is an obvious choice but it isn't available on Windows. "more" kind of works but it's a shell (cmd.exe) built-in command on Windows so not suitable either. I was wondering if anybody has any thoughts on
1. Are there any other Windows commands that might be suitable for this?
or
2. Might it be a worthwhile idea to include a simple program with GRASS that did this (copies everything from stdin to stdout) so we can be sure what's going on?

I know I could get this working some hackish way but would like to do it as elegantly as possible - so it would be great if we can come up with something.

Paul

Paul and Glynn,

I just want to thank you guys for the work you are coordinating to make
wingrass a reality. Although I don't use Windows, getting GRASS to run on
Windows will make it easy for me to require this for all classes using GIS.

Cheers
Michael
__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics & Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

From: Paul Kelly <paul-grass@stjohnspoint.co.uk>
Date: Mon, 13 Nov 2006 22:14:20 +0000 (GMT)
To: <grass-dev@grass.itc.it>
Subject: [GRASS-dev] Merging stdout and stderr

The GRASS console thing (I guess that's where the name gronsole comes
from?) which runs commands via the Tcl/Tk "open" command and captures
their stdout and stderr, displaying some output as-is to the gronsole
window and catching certain things like percentage complete and warnings
and displaying them differently is actually quite cool.

I remember discussion on the list about how stdout and stderr had to be
merged because Tcl/Tk has a bug/feature in that it treats anything written
to stderr as an error indicator for the called program. On Unix this
merging is done as follows:
set cmd [concat | $cmd 2>@ stdout]
but the "2>@ stdout" syntax will not work on Windows. A cross-platform
solution would be to use the "|&" redirector instead of "2>@". "|&" means
"pipe both stdout and stderr to stdin of the following command" (see
Running other programs from Tcl - exec, open ). This command could
then copy everything to its stdout and that's what gronsole gets back.

The Unix cat command is an obvious choice but it isn't available on
Windows. "more" kind of works but it's a shell (cmd.exe) built-in command
on Windows so not suitable either. I was wondering if anybody has any
thoughts on
1. Are there any other Windows commands that might be suitable for this?
or
2. Might it be a worthwhile idea to include a simple program with GRASS
that did this (copies everything from stdin to stdout) so we can be sure
what's going on?

I know I could get this working some hackish way but would like to do it
as elegantly as possible - so it would be great if we can come up with
something.

Paul

Paul Kelly wrote:

The GRASS console thing (I guess that's where the name gronsole comes
from?) which runs commands via the Tcl/Tk "open" command and captures
their stdout and stderr, displaying some output as-is to the gronsole
window and catching certain things like percentage complete and warnings
and displaying them differently is actually quite cool.

I remember discussion on the list about how stdout and stderr had to be
merged because Tcl/Tk has a bug/feature in that it treats anything written
to stderr as an error indicator for the called program. On Unix this
merging is done as follows:
set cmd [concat | $cmd 2>@ stdout]
but the "2>@ stdout" syntax will not work on Windows. A cross-platform
solution would be to use the "|&" redirector instead of "2>@". "|&" means
"pipe both stdout and stderr to stdin of the following command" (see
http://www.tcl.tk/man/tcl8.5/tutorial/Tcl26.html ). This command could
then copy everything to its stdout and that's what gronsole gets back.

The Unix cat command is an obvious choice but it isn't available on
Windows. "more" kind of works but it's a shell (cmd.exe) built-in command
on Windows so not suitable either. I was wondering if anybody has any
thoughts on
1. Are there any other Windows commands that might be suitable for this?
or
2. Might it be a worthwhile idea to include a simple program with GRASS
that did this (copies everything from stdin to stdout) so we can be sure
what's going on?

I suggest the latter, i.e. write our own mini-"cat" program. It will
need to explicitly put stdin/stdout into line-buffered mode (pipes are
block-buffered by default).

BTW, 2>@stdout doesn't merge stdout/stderr, in the way that 2>&1 does
in bash. It redirects the process' stderr to wish's stdout; on Unix,
this is typically the terminal from which gis.m was started, but wish
may not have stdin/stdout/stderr channels on Windows.

--
Glynn Clements <glynn@gclements.plus.com>

On Tue, 14 Nov 2006, Glynn Clements wrote:

I suggest the latter, i.e. write our own mini-"cat" program. It will
need to explicitly put stdin/stdout into line-buffered mode (pipes are
block-buffered by default).

I've done something like this - I called it grocat as it's for gronsole and like cat. All seems to work (unfortunately I can only test gis.m on Windows at the minute) so I've committed some more changes to CVS. This includes the earlier changes to create a .bat file for every script on Windows. The batch files are run from Tcl/Tk and if GRASS is run from cmd.exe; the actual scripts are run if GRASS is run from the Msys shell.

Just as a reminder, the batch files invoke the program specified by the GRASS_SH environment variable and append a -c switch and the full path to the script with c:/grass/dist... syntax, followed by any arguments. I'd hope it would work with other shells than Msys too.

Because it is needed even when GRASS is started from the Msys shell (when running gis.m, Tcl needs a .exe, .bat or .com file) I have added GRASS_SH=/bin/sh to Init.sh.

Paul

Glynn Clements wrote:

> 2. Might it be a worthwhile idea to include a simple program with GRASS
> that did this (copies everything from stdin to stdout) so we can be sure
> what's going on?

I suggest the latter, i.e. write our own mini-"cat" program. It will
need to explicitly put stdin/stdout into line-buffered mode (pipes are
block-buffered by default).

see also:
  lib/init/echo.c -> $GISBASE/etc/echo

funny that that outputs to stderr..

Hamish

On Thu, 16 Nov 2006, Hamish wrote:

Glynn Clements wrote:

2. Might it be a worthwhile idea to include a simple program with GRASS
that did this (copies everything from stdin to stdout) so we can be sure
what's going on?

I suggest the latter, i.e. write our own mini-"cat" program. It will
need to explicitly put stdin/stdout into line-buffered mode (pipes are
block-buffered by default).

see also:
lib/init/echo.c -> $GISBASE/etc/echo

funny that that outputs to stderr..

Yes! This would be useful on Windows if it didn't write to stderr, as the Windows echo behaves differently to the Unix one. The comments in the header in the source say it writes to stdout but the earliest CVS version from 1999 writes to stderr. I wonder could we change it. I wonder does anything use it and/or need the stderr functionality...

>>> 2. Might it be a worthwhile idea to include a simple program with
>>> GRASS that did this (copies everything from stdin to stdout) so we
>>> can be sure what's going on?
>>
>> I suggest the latter, i.e. write our own mini-"cat" program. It
>> will need to explicitly put stdin/stdout into line-buffered mode
>> (pipes are block-buffered by default).

Hamish:

> see also:
> lib/init/echo.c -> $GISBASE/etc/echo
>
> funny that that outputs to stderr..

Paul:

Yes! This would be useful on Windows if it didn't write to stderr, as
the Windows echo behaves differently to the Unix one. The comments in
the header in the source say it writes to stdout but the earliest CVS
version from 1999 writes to stderr. I wonder could we change it. I
wonder does anything use it and/or need the stderr functionality...

grass63$ grep -rI etc/echo *
lib/init/echo.c: * $GISBASE/etc/echo [-n] args

grass-5.4.0$ grep -rI etc/echo *
pkg/prototype:f none /opt/GNUgrass/grass5/etc/echo=/opt/GNUgrass/grass5/etc/echo 0775 root bin
rpmspecs/rpm.specs:%{_prefix}/grass5/etc/echo
src/general/init/echo.c: * $GISBASE/etc/echo [-n] args
src.contrib/SCS/scripts/shells/dlg_extract.sh:$GISBASE/etc/echo -n "Enter DEVICE or FILE_NAME for input : "
src.contrib/SCS/scripts/shells/dlg_extract.sh:$GISBASE/etc/echo -n "Enter TOTAL NUMBER of FILES : "
src.contrib/SCS/scripts/shells/dlg_extract.sh:$GISBASE/etc/echo -n "Enter LRECL: "
src.contrib/SCS/scripts/shells/dlg_extract.sh:$GISBASE/etc/echo -n "Enter BLKSIZE: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "Enter NUMBER OF FILE TO EXTRACT: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "Enter No. of Records: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "Enter name for output file: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "ARE THESE CORRECT [y/n]: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "Do you want to EXTRACT another FILE [y/n]: "

so nothing in GRASS 6 uses it.

It would be pretty easy to change it output to stdout and add a flag to
to it to have it output to stderr.

Hamish

Hello Hamish

On Tue, 21 Nov 2006, Hamish wrote:

grass63$ grep -rI etc/echo *
lib/init/echo.c: * $GISBASE/etc/echo [-n] args

[...]

so nothing in GRASS 6 uses it.

Thanks for checking...

It would be pretty easy to change it output to stdout and add a flag to
to it to have it output to stderr.

Done and done. I can use this in the "init.bat" Windows start-up script I'm writing.

Paul

Hamish wrote:

> >>> 2. Might it be a worthwhile idea to include a simple program with
> >>> GRASS that did this (copies everything from stdin to stdout) so we
> >>> can be sure what's going on?
> >>
> >> I suggest the latter, i.e. write our own mini-"cat" program. It
> >> will need to explicitly put stdin/stdout into line-buffered mode
> >> (pipes are block-buffered by default).

Hamish:
> > see also:
> > lib/init/echo.c -> $GISBASE/etc/echo
> >
> > funny that that outputs to stderr..

Paul:
> Yes! This would be useful on Windows if it didn't write to stderr, as
> the Windows echo behaves differently to the Unix one. The comments in
> the header in the source say it writes to stdout but the earliest CVS
> version from 1999 writes to stderr. I wonder could we change it. I
> wonder does anything use it and/or need the stderr functionality...

grass63$ grep -rI etc/echo *
lib/init/echo.c: * $GISBASE/etc/echo [-n] args

grass-5.4.0$ grep -rI etc/echo *
pkg/prototype:f none /opt/GNUgrass/grass5/etc/echo=/opt/GNUgrass/grass5/etc/echo 0775 root bin
rpmspecs/rpm.specs:%{_prefix}/grass5/etc/echo
src/general/init/echo.c: * $GISBASE/etc/echo [-n] args
src.contrib/SCS/scripts/shells/dlg_extract.sh:$GISBASE/etc/echo -n "Enter DEVICE or FILE_NAME for input : "
src.contrib/SCS/scripts/shells/dlg_extract.sh:$GISBASE/etc/echo -n "Enter TOTAL NUMBER of FILES : "
src.contrib/SCS/scripts/shells/dlg_extract.sh:$GISBASE/etc/echo -n "Enter LRECL: "
src.contrib/SCS/scripts/shells/dlg_extract.sh:$GISBASE/etc/echo -n "Enter BLKSIZE: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "Enter NUMBER OF FILE TO EXTRACT: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "Enter No. of Records: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "Enter name for output file: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "ARE THESE CORRECT [y/n]: "
src.contrib/SCS/scripts/shells/dlg_extract.sh: $GISBASE/etc/echo -n "Do you want to EXTRACT another FILE [y/n]: "

That explains a lot about the fact that it writes to stderr, i.e. the
fact that it is being used to display prompts (which should normally
go to stderr), and the fact that the output doesn't normally have a
newline (the program doesn't call fflush(), so the output wouldn't
appear if it went to stdout).

It looks like it was intended as a portable way to use "echo -n ...".
The SUSv2 specification for echo doesn't support any flags; instead,
you need to put '\c' at the end of the string to suppress the newline.
OTOH, the GNU version and the bash built-in don't support the \c
escape.

--
Glynn Clements <glynn@gclements.plus.com>