0

I'm writing a command-line tool that takes a file and modifies its contents. I would like the user interface to be as canonical as possible. So far, I have

$ foobar -h
usage: foobar [-h] [--version] [infile] [outfile]

Some help text.

positional arguments:
  infile         input LaTeX file (default: stdin)
  outfile        output LaTeX file (default: stdout)

optional arguments:
  -h, --help     show this help message and exit
  --version, -v  show program's version number and exit

but I noticed that tools like sed always print to stdout, unless given the -i parameter in which case the input file is modified in-place. Is this a common Unix convention?

8
  • 1
    No, there is no convention. It is good to use similar options as you find in similar tools, but there is no convention. And in past there were more problems: it was important to distinguish: modify in place, with copy, modify, substitute the file Commented Sep 30, 2020 at 15:19
  • 1
    There are different alternative conventions. It depends on how you will use your program and personal preference. Many programs write to stdout and read from either stdin or a file to allow creating a pipeline, e.g. sed command inputfile | sort | uniq -c. Some programs allow the special file name - for stdin or stdout when used as input or output file name respectively. In-place editing like sed's option -i can be problematic because you might lose your original input in case of an error.
    – Bodo
    Commented Sep 30, 2020 at 15:32
  • One interesting case is where you want to process multiple input files to one output file. That makes positional args useless. The usual method there is to have an option like -o outFile, but default to stdout so it can be redirected or piped at the command line. Commented Sep 30, 2020 at 16:12
  • 1
    You can make your program simpler (and more "canonical") by getting rid of the infile and outfile arguments. Simply let read from stdin and write to stdout. The user can use it as prog <file1 >file2, which would also make clear that file2 really is an output, and not another input as with cat file1 file2, and will save users from inadvertently overwriting files. The -i option of sed is broken, and you should not bother with it; you can easily achieve the same effect with prog <file >file.new && mv file.new file || rm file.new.
    – user313992
    Commented Sep 30, 2020 at 20:01
  • 1
    Which is exactly my point ;-) But your comment suggesting (whether intended or not) that sed -i may trash the file in case of error wasn't that far-fetched, considering that it was exactly what perl -i (which was supposed to be similar to sed -i) was doing until quite recently. That's why I felt the need to clarify it.
    – user313992
    Commented Sep 30, 2020 at 22:06

1 Answer 1

1

-i is sed-specific. For, for example, awk it would be -i inplace, and many others don't even support in-place actions.

There are a number of conventions. The most important is, that if no input is given, use STDIN, and if no output is given use STDOUT. But that one you already do.

In general, most programs treat a list of files on the command line as files that must be read. Many programs use -o filename to indicate that the output should go to filename. GNU seems to like --output for this as well.

If you want to explicitly use STDIN or STDOUT, -- seems more or less the standard way of specifying that.

But then, there are many programs that do not follow this convention. Some use the last positional argument for the output. Some us -- to indicate that the rest of the command line only contains files, and some (like dd) have created their own standard.

So, if I were you, I'd stick with -o and --output for the output file and use -- for STDIN or STDOUT. And write a clear man page, so your program becomes predictable.

You must log in to answer this question.

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