0

Is there any rule of thumb when the result of the program should be printed to the stdout by default, and when the more appropriate approach is to accept output file as one of the arguments and write to it? One can always redirect the stdout to a file.

I know that there are different programs, and for example it does not make sense to print to the stdout if the result is multiple files, not a single one. It also does not make sense to accept output file as an argument if the output of the program has temporary nature.

However, what about programs producing output that ultimately should be placed in a single file? Such programs can be further divided into programs accepting input from the stdin and the ones taking input from arguments.

8
  • This is pretty much done at the preference of the programmer - you'll likely only get opinion based answers to this question, instad of facts.
    – Panki
    Commented Apr 12, 2021 at 7:45
  • If you're not sure, why not print to stdout by default and add an optional --output, -o option?
    – pLumo
    Commented Apr 12, 2021 at 8:10
  • @pLumo, as such approach would be redundant, one can always redirect stdout to file.
    – Al Bundy
    Commented Apr 12, 2021 at 8:45
  • But then the user can decide, as obviously the programer (you) are not sure.
    – pLumo
    Commented Apr 12, 2021 at 8:51
  • 1
    A general guideline for writing unix programs is: Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input. -- Doug Mcllroy, Bell System Technical Journal, 1978. en.wikipedia.org/wiki/Unix_philosophy
    – cas
    Commented Apr 12, 2021 at 11:14

2 Answers 2

2

A few practical examples:


An application sending its output to stdout typically implies that the application works just fine with any type of recipient, it just sends a stream of data suitable also for a pipe or a socket. This is the very essence of Unix pipelines, so if there is any rule of thumb then this one is probably the best candidate.


On the other hand, though, a -o <output-file-name> option is typically preferred if the application rather needs to seek over its output.

Of course you can lseek(2) over stdout too (if it is indeed seekable), but that's conventionally unexpected behavior.

Naturally the same holds for input as well.


Redirecting from/to a file requires a shell. A dedicated option argument allows for not requiring a shell.


Redirecting from/to a file enables easy sharing of that file's position (if it is seekable) or that pipe/socket's connection among several applications, which can be a useful feat in shell scripting, such as in:

{
    echo hello world
    head -c 10
    seq 10 | awk '{print "amazing text-manipulation of", $0}'
    dd bs=1024 count=1 seek=32
    echo farewell
} < /dev/random > recipient-file

Relying only on a -o recipient-file option (or -i /dev/random) would not allow that (so easily).


In some cases the opposite of the above may also hold: a -o <output-file-name> option allows for making that application's output not pollute stdout while sharing it with other applications, such as in:

strace -o prog.strace output-producer > prog.output

The same holds for input, for having an application not consume a shared stdin.

unwanted-consumer -i /dev/null desired-consumer

Relying only on stdin/stdout would require an additional layer of shell, like in:

strace > prog.strace sh -c 'output-producer > prog.output'

or for stdin:

unwanted-consumer 3<&0 < /dev/null sh -c 'desired-consumer <&3'

Apart from compactness/cleanliness of the command, and apart from requiring a shell at all, invoking a shell involves a somewhat different environment and you might need to adjust that for output-producer or desired-consumer, increasing the overall burden.

2

If you can imagine the output of the program being used as input to another, and if the output is basically text, then defaulting to stdout lets the program be easily used as part of a pipeline.

On the other hand, if the output is usually binary, or very large (compared to inputs given), then it can make sense to ask for a filename by default, and refuse to print on the terminal unless explicitly asked.

For the first group, consider grep, sort, cut and such which work equally well as part of a pipeline feeding another program, and as giving output read directly by the user. Pretty much everyone knows they print to stdout and are used to redirecting the output to a file if they want that.

For the second, consider e.g. convert from ImageMagick, which can convert and process image files. It takes the input and output filenames on the command line. Here, it's rarer for the image file to be used as part of a pipeline, and in practice, one never wants a JPEG or PNG dumped to their terminal, so here it makes sense to do it that way.

When taking filename arguments, it may be a good idea to let - stand for stdin or stdout, provided that you document this. It's a rather common custom, and saves the user from having to use something like /dev/stdin instead. (And that could fail in some systems.)

Doing what other tools do is good in that it leaves less room for surprises. Unless of course your use case is different enough that copying others doesn't make sense.

Not the answer you're looking for? Browse other questions tagged .