Error message output

Polytropon freebsd at
Tue Sep 22 15:31:58 UTC 2020

On Mon, 21 Sep 2020 23:33:50 -0700, David Christensen wrote:
> On 2020-09-21 15:55, Polytropon wrote:
> > On Mon, 21 Sep 2020 15:33:40 -0700, David Christensen wrote:
> >> On 2020-09-21 04:21, Polytropon wrote:
> >>> On Sun, 20 Sep 2020 22:12:24 -0700, David Christensen wrote:
> >>>> On 2020-09-20 10:11, Polytropon wrote:
> >>>>> I have a general question. Is it still considered useful to
> >>>>> output error messages of a script to standard error?
> > Example (from a real script); the following normal usage
> > prints to standard output:
> > 
> > 	% mdcc_rg_2020-04-01
> > 	 + mdcc_rg_2020-04-01_1.png
> > 	 + mdcc_rg_2020-04-01_2.png
> > 	 + mdcc_rg_2020-04-01_3.png
> > 	-> mdcc_rg_2020-04-01.pdf
> So, reads mdcc_rg_2020-04-01_1.png, mdcc_rg_2020-04-01_2.png, 
> and mdcc_rg_2020-04-01_3.png, and writes mdcc_rg_2020-04-01.pdf?

Correct: You provide a "pattern" (i. e., "starts with", the shell
does the expansion of *), and the output file drops the "counter"
and is a PDF file containing the scanned sheets, so it's easier
to transfer and print. :-)

> I would drop the '.sh' extension.

Will do, especially as it's now in /opt/bin, a reason to be
optimistic. :-)

> Providing a fractional base file name as an argument and computing input 
> and output file names is unconventional.  The FreeBSD convention seems 
> to be to use complete file names for arguments.  This allows the user to 
> use shell globbing, find(1) and xargs(1), etc., or to wrap this script 
> in another script that computes the arguments.

In this case, the calling shell would have to do it. I do not
expect csh or bash or zsh doing that differently from plain sh,
but you never know... :-)

> As this program operates on entire files and those files are binary, it 
> is tempting to allow input file names on stdin.  I think this idea is 
> unconventional and better avoided.

Programs like cpio do this. Programs that operate on a set of
files typically get them via command line, while programs that
operate on _one_ file from a set of file often have their "list
generator" prefixed, like "something | xargs -n 1 progname".

> So, I'd go with positional arguments for the input and output file names.
>      % png2pdf mdcc_rg_2020-04-01*.png mdcc_rg_2020-04-01.pdf

The key is that the output filename is "automatically" assigned
("base name without counter"). In such a case, I'd even go for
an optional argument for the output file, such as cc does:

	% cc blah.c

generates a.out, but

	% cc -o blah blah.c

generates blah as the output binary; -o is optional.

> When the argument list contains two (or more) kinds of things, it can be 
> useful to pick one kind for arguments and to pass everything else via 
> options:
>      % png2pdf -O mdcc_rg_2020-04-01.pdf mdcc_rg_2020-04-01*.png

The advantage of having the invoking shell define the input files
is that it enables the user to combine files with different "base
names", such as:

	% png2pdf -o report.pdf blah_01.png blah_02.png foo_*.png end.png

I think this is a good idea for further improvement.

Both concepts also work nicely with shell completition:

	% png2pdf foo[TAB]
	  png2pdf foo_2020-01-23_ <adding>
	  png2pdf foo_2020-01-23_*.png

In case there are no offending files of other types, "*" can
be the last symbol.

> My scripts emit '+' in the first position only when they have invoked 
> sh(1) with xtrace enabled.  Outputting '+' otherwise is confusing.

Never heared of that concept...

I thought it was good to use "+" for "adding", and "->" for "to
the result"; maybe "=" or even ":=" would have been possible too,
even though I tried hard to unlearn ":=". ;-)

> If I wanted to see the input file names as they were processed, I would 
> add a verbose option and preface each input file name with "reading". 
> The messages would to to stderr.

Or the opposite approach: -q (quiet) if you don't want those.
Or compare cp to cp -v.

> My similar scripts typically print (to stdout) the bare names of files 
> and directories that they change.  If there were multiple possibilities 
> -- "writing", "appending", "creating", "updating", "deleting", etc. -- I 
> would add prefaces.  The messages would go to stdout.
> Messages for files that are not changed would be handled by verbose 
> option messages -- "skipping", etc..  The messages would to to stderr.
> It is nice to have a quiet option suppresses all output except fatal 
> error messages.
> For exit value, I use 0 for correct operation and 1 for everything else.

As suggested by sysexits.h, it's possible to signal the kind
of error to the caller. This is not standard in sh scripts,
but can be used there.

> > The typical error cases (input not found, no input specified)
> > output to standard error, and there is a non-zero exit code:
> > 
> > 	% nothing
> > 	Error: no matching source files for pattern nothing_*.png found, aborting.
> The FreeBSD convention seems to be to print the usage message when given 
> bad options or arguments:
>      Usage: [-v] [-q] infile... outfile
>    [-v] [-q] [-O outfile] infile...

That is correct, and the system tools tend to follow that
convention. Existing man pages and the templates suggest
this style. Oh, and I should probably write a manpage, too. :-)

> > 	%
> > 	Convert PNG image files and create PDF
> > 	Usage: /opt/bin/ <pattern>
> > 	The source file pattern must lead to files named <pattern>_*.png.
> > 	The target file's name will be <pattern>.pdf.
> When given no options or arguments, the FreeBSD convention seems to be 
> to run the program with a default argument.  If no default makes sense, 
> then to print the usage message.

For the tool in question, the usage message would be the
default, as one cannot assume any valid input. :-)

Thank you for inspiration and further education. It's
always nice to learn something new or reconsider something
learned and / or long forgotten.

Magdeburg, Germany
Happy FreeBSD user since 4.0
Andra moi ennepe, Mousa, ...

More information about the freebsd-questions mailing list