Commands - Historical Basics
This note contains basics of historical Unix command line syntax. Most of this applies even to this day if nothing else is stated. This explains the "why" behind some of modern command line conventions.
If a program is given unnamed arguments, those were filenames to be used as input.
cat <<EOF > greeting.txt
hello world!
EOF
cat <<EOF > farewell.txt
bye you!
EOF
wc greeting.txt
# 1 2 13 greeting.txt
wc farewell.txt
# 1 2 9 farewell.txt
wc *.txt
# 1 2 9 farewell.txt
# 1 2 13 greeting.txt
# 2 4 22 total
The program output would be written to the standard output. This allows chaining or "piping" of commands.
If no filenames were given, it would read the standard input. This is common to this day.
wc
# will open a text prompt so you can write your input
cat *.txt | wc
# 2 4 22
# but now has no knowledge of the filenames as the data was piped through standard input
Single Dash Options
Originally, options always started with a single dash and be a single character. This made parsing simple. The option value could be right after the character or be the next argument.
cat *.txt | sort -r
# hello world!
# bye you!
cat *.txt | sort -k1
# bye you!
# hello world!
cat *.txt | sort -k2
# hello world!
# bye you!
cat *.txt | sort -k 2
# hello world!
# bye you!
Multiple single character options could be "packed". For example, -a -b -c
could be shortened to foo -abc
.
cat *.txt | sort -k2r
# bye you!
# hello world!
Soon it was realized longer option names will be required. For example, if you have display
and depth
which would logically both be -d
, and you will eventually run out of characters in a more complex program.
But this caused:
- Packing became situational as
-depth
could also mean-d
,-e
,-p
,-t
,-h
, thus is became responsibility of the program to parse and communicate usage correctly. - You can't uniformly parse option values without knowing the option names if there is no space between the option name and value e.g.
-d1
,-d 1
and-depth 1
are valid but-depth1
is incorrect (if the 1 is value and not part of the name.)
Double Dash Options
Later, double dash --
became to communicate a long option. Initially the long option marker was +
but that is rare to find nowadays.
--help
--color auto
Around the same time, equals sign =
became the optional way to specify value. This made creating universal parser much simpler.
--color=auto
Then order of options and other arguments became less strict. Before this, options must've been defined before other arguments (i.e. filenames.)
grep -xi *.txt --regexp=foo --regexp bar
# obs. the beginning is expanded to `-x -i`
Double Dash Termination
Empty double dash --
became to signify "no further options". It was realized that some situations were impossible without a way to terminate options manually.
# if you want to delete a file name `-f`
rm -- -f
# also useful if you run a program that runs another program with options
cargo run -- --version
Subcommands
Subcommands were a simplification of exclusive options. Exclusively checking for e.g. app --encrypt
or app --decrypt
was a bit tedious to both use and validate by the programmer. Using first unnamed arguments as "subcommands" instead of filenames became the norm for early version control software and has since become a standard practice for more complex command line tools.
git --help # show help for the whole `git`
git status --help # show help for `status` subcommand
git add --help # show help for `add` subcommand