While passing information to command line programs with environment variables is a model that’s both powerful and elegant, it’s not without its problems. Possibly the worst of them is the total lack of feedback of any kind on user error. Can you tell which of these is right?
GPGHOME=~/.gnupg/ gpg --list-secret-keys # or GNUPGHOME=~/.gnupg/ gpg --list-secret-keys
Well, the executable is called “gpg” so the first one seems to make sense, but the suite is named “GnuPG”, so the second seems like a reasonable assumption as well.
The answer is that
GNUPGHOME is right, despite the executable’s naming. But
far more offensive than that design is what happens when you pick the wrong
one: GPG doesn’t even acknowledge that there might be a problem and silently
behaves as if you hadn’t specified anything at all.
As I was attending Heavybit’s Devguild earlier this week, Rob Szumski pointed
out that Etcd solves this problem by verifying not just its command line flags,
but its env vars as well. It assumes ownership of any env var with a prefix of
ETCD_ and notifies the user when:
- When an env var with a prefix of
ETCD_has been specified, but which the program doesn’t know about.
- When an env var has been specified, but “shadowed” by a flag which has equivalent meaning but whose value has taken precedence.
Neither problem produces an error (the first is a warning and the second a notice) so that the program stays backward compatible even if a new version of Etcd removes an env var that a user was sending a value in for. Here’s the code that accomplishes the effect.
This design wouldn’t directly solve the
GNUPG problem above, but I
would suggest that in its spirit a well-designed GPG look for
env vars as well, and show a warning when a user tries to use one.
I’m a huge supporter of these minor tweaks to the “old ways” of CLI design that have a disproportionately positive impact on improving usability compared to the effort required to implement them. More information is always better.
Did I make a mistake? Please consider sending a pull request.