System administration
ORGANIZING YOUR BASH PATH
If you've ever looked at your .bashrc
file and wondered how the heck
it got so weirdly out of control, look no further than the slow
migration of "local changes" to the .local
folder, and the number of
language– or framework-specific environments that are now kept there.
There's much to recommend this move, not the least of which is
decluttering the $HOME
directory. But my biggest pet peeve was the
$PATH
variable, which seemed to just grow and grow in my .bashrc
file into an unreadable string. I've decided to fix that. Here's how.
I had recently added Google Go to my list of environments, and I couldn't figure out where to add it into the PATH. I mean, look at this beast:
export PATH="/home/elf/.pyenv/plugins/pyenv-virtualenv/shims:/home/elf/.pyenv/shims:/home/elf/.cargo/bin:/home/elf/bin:/home/elf/.local/bin:/home/elf/.local/lib/yarn/bin:/home/elf/.pyenv/bin:/home/elf/.local/lib/npm-packages/bin:/usr/local/bin:/snap/bin:/opt/wine-stable/bin:/usr/bin:/bin:/usr/games:/usr/local/go/bin"
There are two things I wanted to do: break that massive path variable into a readable and manageable list of paths, and then join the elements of that list together into an exportable string with a minimal amount of code.
So the first thing to know is that bash has arrays! They're not the world's greatest thing, but they're fit for this purpose. I took my path and broke it up into a local PATHS array:
PATHS=(
"/bin"
"/usr/bin"
"/home/elf/bin"
"/home/elf/.cargo/bin"
"/home/elf/.local/bin"
"/home/elf/.pyenv/bin"
"/home/elf/.local/lib/yarn/bin"
"/home/elf/.local/lib/npm-packages/bin"
"/home/elf/.local/share/go/bin"
"/usr/local/bin"
"/snap/bin"
"/opt/wine-stable/bin"
"/usr/games"
)
That's a HECK of a lot more readable, no? (I know, I know, it's probably an awful mess, but it's my mess, and at least it's somewhat organized.)
Now how do we export that as the PATH
?
I recalled that awk
has field and record separators, and while I was
searching to see if I could use awk as a way of assembling the string, I
discovered that bash has a field separator control! As long as the field
separator is a single character you can use it to control the rendering
of a bash array. I'll admit up front I don't know if that's "ASCII
character" or "Unicode character" or "Unicode code point", and for my
purposes it doesn't make a difference, since the path separator symbol
is the colon, hex 0x3A, which makes it fit easily in UTF-8, but it might
for someone with other linguistic needs.
Anyway, it's easy to turn the array above into a single string:
export PATH=$( IFS=":" ; echo "${PATHS[*]}" )
The $()
construct isolates the rendering into a separate process, sets
the field separator to a colon, then echos out all the contents of the
PATHS
variable separated by the field separator. The resulting string
is then exported as PATH
.
And that's how you use bashisms to help organize your shell code into more readable chunks.
Postscript: It's professional malpractice if you're writing a lot of bash and you're not using shellcheck. Just sayin'. It could save you a lot of grief.