21 ms·
I find myself using environment variables much more than commandline arguments when writing CLI programs: - Env vars provide a key/value interface, which is tr
by chriswarbo 10y ago
I find myself using environment variables much more than commandline arguments when writing CLI programs:
- Env vars provide a key/value interface, which is trickier to handle with arguments (e.g. "get the argument immediately after '-f'").
- Env vars are in-scope at the point they're needed, whereas non-trivial arguments usually have to be parsed up-front all at once and passed into the processing code somehow. Yes, it's good to check things up-front; we can check mandatory/mutually-exclusive env vars up front too, with the bonus that we can keep such 'invocation checking' separated from the rest of the processing.
- Setting env vars in preparation for a subprocess call can be done incrementally, by extending the environment over and over until we're ready. In contrast, commandline arguments must be accumulated into a single (correctly parsable) array.
- Sharing env vars across a program and its children is easy (e.g. "VERBOSE=1 ./foo.sh").
- We can use env vars to control a program even when it's called deep in the bowels of something else, without having to fiddle with all of the layers in between.
I find this works very nicely, as long as we:
- Treat the environment as append-only, i.e. no changing a variable once it's been set. We can append new variables, e.g. "export FOO=bar", and we can invoke processes with extra variables, e.g. "FOO=bar ./baz.sh", but we don't unset or alter a variable.
- Don't use env vars for communication within a process, i.e. we can use the environment variables we're invoked with, and we can append new variables for use by the programs we invoke, but within a program we should refrain from setting variables which affect our own execution (since that causes the coupling and spooky-action-at-a-distance which globals are notorious for).
What are others' thoughts on this?
- vram22 10y agoInteresting. I'll have to parse (heh) your comment, but for now, can say that IIRC, environment variables, command line options, and one other thing (maybe config or .*rc - for Run Command - files, such as .exrc, .vimrc, .bashrc) are supposed to form a hierarchy, such that A can override B can override C (something like global and local CSS styles). And out of two of them at least, command-line options can override the values of environment variables, maybe since they can be changed more easily on a per-command-invocation basis.
- dllthomas 10y agoI think if we make too much of a habit of this, we'll wind up with painful collisions. It also does the wrong thing with no feedback if you try to set a shell variable that isn't actually recognized (and possibly if you misspell the option name, &c). That said, I agree that it can work quite nicely in the small, but it should probably be reserved for things like VERBOSE where you are likely to want propagation. > Env vars provide a key/value interface, which is trickier to handle with arguments Many (most? all?) languages practical for assembling a shell utility have a getopt-ish library that should make this easier (though still likely not as easy as grabbing from a shell var, granted).
- vacri 10y ago> (e.g. "get the argument immediately after '-f'") Is there a language commonly used for cli tools that doesn't have an inbuilt options lib? Even bash has inbuilt 'getopts' to handle this for you. while getopts "ab:" option; do case $option in a) VAR="foo";; b) VAR2="$OPTARG";; esac done shift $((OPTIND-1)) which will allow you to "myscript -a -b myarg" By all means, use env vars if it works for you, but it should be right tool for the right job. Imagine trying to use 'ls' with env vars...
- beefhash 10y ago> Is there a language commonly used for cli tools that doesn't have an inbuilt options lib? Yes, namely C/C++ under the Visual Studio toolchain: https://stackoverflow.com/a/12689342 https://stackoverflow.com/a/12689342
- vacri 10y agoI stand corrected. I thought I might get burned by C, but didn't expect it to bring Windows in on the action :)