What are some of the best and worst command-line interfaces you have used?
From the time I was a teen I think I remember that mount was difficult to use, and mounting a CD image required passing some arcane options, though maybe I just didn't know how to use it (on the other hand I didn't know how to use Daemon Tools either, and it just worked).
I don't have a problem with git though. I don't think it's the command-line interface that's hostile, it's git itself if you don't know what you're doing. After taking some time to learn it I actually enjoy solving difficult problems with git.
By default (without specifying extra command-line options) it overwrites the input files. [1]
In decades of computer use, that is the only command line tool that tricked me into destroying my data because I didn't realize it works differently from all the other tools I use that don't do that.
Usually, a command line utility with less options specified is relatively "safe" and you have to add extra syntax to make it "unsafe".
It was definitely a violation of: https://en.wikipedia.org/wiki/Principle_of_least_astonishmen...
EDIT reply to: >The whole reason for mogrify's existence is that it overwrites the original image file.
Sure, I understand that but many other destructive tools will have safety UI features such as creating ".bak" backup files. That's what many other command line tools do including image utilities. So something like mogrify could have been designed with hypothetical syntax as "mogrify -nobackups". The principle is to type extra syntax to make it more dangerous while still accomplishing the (observable) goal of changing the original files.
[1] https://superuser.com/questions/1575004/imagemagick-how-to-a...
For interactive shell scripting:
- AWK. Old enough to be part of the POSIX standard and yet considerably more awesome than almost any other UNIX command.
- socat for any kind of network/socket testing stuff.
- sponge and entr just for their genuine usefulness with minimal interface.
For interactive use:
- SSH. I mean, obviously. It's also astounding how well OpenSSH integrates into the whole *NIX TTY landscape. You can use it for years and still learn neat things about it.
- Vim. Yes, it's obscure to learn, but once you do, boy do you get a lot out of it. Also: Since `:terminal`, working on one-off scripts has become considerably more awesome.
- htop and btop++ are good examples of TUIs for interactive use.
- tig is also quite cool for many git interactions (especially partial staging).
- lnav for log analysis tasks.
For batch jobs you set up and trigger as needed:
- Beets (see: beets.io). It's impressive how streamlined it works once you've set it up.
Bad:
- Pretty much anything Microsoft. I really don't understand how it's possible to consistently produce bad CLI programs for such a long time.
- As a prime example, have a look at `sc sdshow` and `sc sdset`.
Edit: Perhaps to clarify about the sc SDDL commands:
If you look them up, you won't find much "bad" in their documentation. Because nothing about the SDDL syntax they are built on is documented. The best you can do is scrape together what you can from third-party blogposts with a perceived signal:noise ratio of .000001.
And SDDL in itself is phenomenally badly designed. And, of course, this being Microsoft, the tool isn't designed to be used together with other programs.
i'm used to it now but when I was learning, "what the fuck did `git reset --hard` do? where is --soft? Is there a no-flag version? What the fuck did I leave mercurial for. God damn I miss svn."
I still kind of miss Mercurial and TortoiseHG.
EDIT: Oops backspace works. Might have been a combination of putty and sqlplus. Nevermind.
The worst: I used to work with an awful custom-built industrial computer.
You had to enter the 10-character alphanumeric codes of 98 rail cars into a command-line interface that didn't permit backspacing. One mistake. Car 97. Do it all again.
1. They used differing return values for success and failures. Sometimes, a 0 was a success, sometimes 1 was a success, and sometimes only 4 was a failure, but everything else was a success.
2. They used different command-line switch formats. Some utilities used a hyphen, others used a forward slash.
Kubectl is among the best: commands make sense and have internal logic, interface is discoverable, output is configurable and supports different formats.
Maybe a good command line user interface is one you don't notice nor remember. It just work smoothly. So I will start with cat.
Git does this but is workable because it’s 2 levels and you don’t need to specify various flags defaults are usually ok
I mostly discover flags with tab completions and the attached help to it (maybe that's only a zsh feature not sure if other shell have help on flags on completion)
bonus point to very smart completion, i.e: on kubectl if i do kubectl -n foo get pods [TAB] it will get the tab from the namespace foo on completion not from the default/current namespace.
The only pity is that mosh breaks compatibility with earlier versions once in a while.
I do like anything that's a nice well-structured representation of an API though – things like the AWS CLI are pretty good in practice, IMO.
If you mean TUI wise as in curses, nearly all of them.
Command line parameters however, there are so many examples. Tar, unrar and unzip take the cake, all in the same category of tools. "unrar x" whatever it is, I always have to look it up. dd because of the way its parameters are specified: dd if=/dev/zero of=foo.bar bs=4096 count=1024 . It's all historical and I can live with it, but many of them at least have the saving grace that they have excellent manpages or you've used them so often it becomes second nature.
There should be a special place in hell for tools that combine short and long style command line options with a single dash. Like "foo -b a -r -baz 123" with "-baz" being a single option, because I will automatically add an extra dash there out of habit.
Coworkers discovering ncurses or some library around it tend to go on a TUI frenzy for a while, and it inevitably ends up being some convoluted mess nobody wants to use. I'll admit there's a few indispensable curses based tools, for instance top (and some variants along that line), but they're far and few in between. At most dialog comes to mind for dealing with prompts for end users, but I personally abhor it in anything but a setup or installation context.
Those very same coworkers also make tools with indecipherable command line options, often because they don't know the language they're working in has a standardized option parser library or module.
> best
I don't remember which tool it was, it could be "crm" (for failover, think like heartbeat and pacemaker) but I might be mistaken. It's been years since I've used it. The command line had options like so:
tool [options] section action resource_src resource_tgt
But the best part was, if you just started the tool without any options, it'd drop you into a pseudo-shell. It'd show you a blank prompt ending in ">". If you then typed "section" you'd end up with a "section>" prompt.
I remember for what I was doing with it, it felt really intuitive. At any point I could type "help section" and it'd list the available actions for that section, together with short example.
I've forgotten the real syntax, but you'd have commands like:
tool node status
tool node standby servername
tool service stop dns
tool service migrate dns secondary
If you were in the pseudo-shell, you could do:
$ service
service$ migrate dns secondary
service$ up
$ node
node$ status
node$ exit
Why: it didn't force you to read man pages or look up documentation, but instead allowed every command to explain what it does to you, either when you'd run it with --help, or just no parameters (in case it expects any). Furthermore, invocations of these commands weren't just a long string of arguments, but rather commands that are logically grouped and can essentially be navigated as a tree. All of that made it extremely useful and pleasant, at least in my eyes.
It just feels like it's made to actually be used by developers and to help them as much as possible. Whether you agree with me on that or not, i suggest that you have a look at this excellent talk by Dylan Beattie, "Life, Liberty and the Pursuit of APIness: The Secret to Happy Code", which talked more about the discoverability of systems and the developer experience: https://www.youtube.com/watch?v=lFRKrHE8oPo
Nowadays, you can actually use something like Typer for Python to create similarly useful interfaces, which i strongly advise you to have a brief look at: https://typer.tiangolo.com/
Example:
$ docker
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
... (a list of items)
-v, --version Print version information and quit
Management Commands:
... (a list of items)
image Manage images
Commands:
... (a list of items)
Run 'docker COMMAND --help' for more information on a command.
To get more help with docker, check out our guides at https://docs.docker.com/go/guides/
$ docker image
Usage: docker image COMMAND
Manage images
Commands:
... (a list of items)
ls List images
... (a list of items)
pull Pull an image or a repository from a registry
Run 'docker image COMMAND --help' for more information on a command.
$ docker image pull
"docker image pull" requires exactly 1 argument.
See 'docker image pull --help'.
Usage: docker image pull [OPTIONS] NAME[:TAG|@DIGEST]
Pull an image or a repository from a registry
$ docker image pull alpine:3.15
3.15: Pulling from library/alpine
59bf1c3509f3: Pull complete
Digest: sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300
Status: Downloaded newer image for alpine:3.15
docker.io/library/alpine:3.15
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine 3.15 c059bfaa849c 11 hours ago 5.59MB
The worst: tarIn short, it's the exact opposite of the previous example. Frankly, without memorizing the flags, i still have no idea how to work with archives with it. Say, i want to create a compressed archive with it.
Example:
$ tar
tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options
Try 'tar --help' or 'tar --usage' for more information.
$ tar --usage
Usage: tar [-AcdrtuxGnSkUWOmpsMBiajJzZhPlRvwo?] [-g FILE] [-C DIR] [-T FILE]
[-X FILE] [-f ARCHIVE] [-F NAME] [-L NUMBER] [-b BLOCKS]
[-H FORMAT] [-V TEXT] [-I PROG] [-K MEMBER-NAME] [-N DATE-OR-FILE]
... (a really long list of items)
$ tar --help
Usage: tar [OPTION...] [FILE]...
GNU 'tar' saves many files together into a single tape or disk archive, and can
restore individual files from the archive.
Examples:
tar -cf archive.tar foo bar # Create archive.tar from files foo and bar.
tar -tvf archive.tar # List all files in archive.tar verbosely.
tar -xf archive.tar # Extract all files from archive.tar.
Main operation mode:
... (a list of items)
-c, --create create a new archive
Operation modifiers:
... (a list of items)
Local file name selection:
... (a list of items)
File name matching options (affect both exclude and include patterns):
... (a list of items)
Overwrite control:
... (a list of items)
Select output stream:
... (a list of items)
Handling of file attributes:
... (a list of items)
Handling of extended file attributes:
... (a list of items)
Device selection and switching:
... (a list of items)
-f, --file=ARCHIVE use archive file or device ARCHIVE
Device blocking:
... (a list of items)
Archive format selection:
... (a list of items)
FORMAT is one of the following:
... (a list of items)
Compression options:
... (a list of items)
-z, --gzip, --gunzip, --ungzip filter the archive through gzip
Local file selection:
... (a list of items)
File name transformations:
... (a list of items)
Informative output:
... (a list of items)
-v, --verbose verbosely list files processed
Compatibility options:
... (a list of items)
Other options:
... (a list of items)
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
The backup suffix is '~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.
The version control may be set with --backup or VERSION_CONTROL, values are:
... (a list of items)
Valid arguments for the --quoting-style option are:
... (a list of items)
*This* tar defaults to:
--format=gnu -f- -b20 --quoting-style=escape --rmt-command=/usr/lib/tar/rmt.exe
--rsh-command=/usr/bin/rsh
$ # Copied from the Internet, because the documentation is overwhelming
$ tar -vczf new-archive.tar.gz ./files-i-want-to-archive
./files-i-want-to-archive/
./files-i-want-to-archive/test1.txt
./files-i-want-to-archive/test2.txt
./files-i-want-to-archive/test3.txt
$ # Consider the full format instead, maybe we should actually use the full parameters more often?
$ tar --verbose --create --gzip --file=new-archive.tar.gz ./files-i-want-to-archive
In short, using tar does not inspire joy and it feels overcomplicated, no matter how you look at it, possibly either because creating archives is a complicated domain (though the zip tool might not necessarily support that claim), or because the tool has grown over time and no longer does just one thing and does it well.