2

I'm writing a script to troubleshoot problems that I encounter regularly.

One of the issues is /sbin missing from the path. But it's not always the case, so instead of indiscriminately adding it to .profile, .bash_profile, .bashrc, etc. like so:

echo "export PATH=\"$PATH:/sbin\"" >> ~/.bashrc

..and over time, ending up with multiple export PATHs with :/sbin:/sbin:/sbin:/sbin:/sbin on the end... well, you get the idea. How do I manage this?

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
voices
  • 495
  • 6
  • 20

3 Answers3

7

Here's one way:

echo '[[ ":$PATH:" == *:/sbin:* ]] || PATH="$PATH:/sbin"' >> ~/.bashrc

(Note that you don't need the export, by the way, when updating what is already an environment variable.)


How it works:

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • Thanks, that's probably what I'm looking for. Would you mind elaborating a bit on how that works? – voices Sep 29 '18 at 03:38
  • You still need the export if you want subshells to pick up the updated version, no? +1 either way. This is very elegant. – Mad Physicist Sep 29 '18 at 03:56
  • 2
    @MadPhysicist: Nope; you can try it for yourself. Per the documentation, `export` marks a function or variable to be passed to child processes; it does *not* specifically mark its current value. If you continue to change the variable's value after it's been `export`-ed, then you continue to change what is passed to subprocesses. – ruakh Sep 29 '18 at 04:40
  • also, `echo` should probably be on the other side of the `||`, right? – voices Sep 29 '18 at 04:44
  • @ruakh. TIL. I appreciate that. – Mad Physicist Sep 29 '18 at 04:52
  • @tjt263: I wrote this answer based on my best understanding of what you wanted. If you wanted something a bit different, please adjust as needed. – ruakh Sep 29 '18 at 05:47
1

This may not be the "best" solution, but one I'm quite comfortable with. I've always liked using Python for my repetitive tasks that it would take too long to do properly in bash, and this definitely fits the bill.

The idea is to check if /sbin is present in $PATH, delimited by the start or end of the string, or a colon. grep or even extended test ([[) can do this for you pretty easily, but for a general solution, where the path of interest may have regex control characters, or you would have to escape parts of the string. It's much easier in Python than in bash: Is it possible to escape regex metacharacters reliably with sed. So I use a script like this (which actually avoids almost all manual parsing):

inpath

#/usr/bin/env python
"""
Checks if the sole argument is in the PATH.

Returns 0 if yes, 1 if no. It is an error to pass in more
than one command-line argument.
"""
import sys
from is import get_exec_path
from os path import abspath, normcase

if len(sys.argv) != 2:
    raise ValueError('Exactly one command line argument must be provided')
path = [normcase(abspath(p)) for p in get_exec_path()]
sys.exit(sys.argv[1] not in path)

This can be implemented in any number of languages more simply than in bash; I just happen to be familiar with Python. It should work with any sane version, probably before even 2.6. It's written to run on Unix or Windows, although I'm going to guess that it's not really useful on the latter. Use it like this:

if inpath /sbin ; then
    echo "export PATH=\"$PATH:/sbin\"" >> ~/.bashrc
fi

Or

inpath /sbin && echo "export PATH=\"$PATH:/sbin\"" >> ~/.bashrc
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • Python makes this certainly much more elegant. But I'd hesitate to have e.g. my `.bash_profile` depend on an external Python script. Why is bash such a horrible language? – A. Donda Jan 21 '22 at 22:18
  • @A.Donda. Bash is made for shell scripting, so it gets awkward for things like complex string manipulation or math. That doesn't make it horrible, just not optimally suited. When's the last time you used a machine running bash without at least a basic python install? – Mad Physicist Jan 22 '22 at 00:08
  • I'm sorry, but bash language is horrible, not just in this particular case. I don't know any other language where I have to look up things every single time I use it. – A. Donda Jan 22 '22 at 19:55
  • 1
    @A.Donda. Any language you're new to, or don't use often, is like that. Bash is not great, but it serves a purpose, and does it reasonably well. That being said, there's a reason I'm suggesting using python. It's ubiquitous enough to be able to use it fairly portable. – Mad Physicist Jan 22 '22 at 19:57
  • Agree to disagree? I have used bash for many years, and fairly regularly. – A. Donda Jan 22 '22 at 20:03
  • 1
    @A.Donda. No, I agree :) I was trying to be nice to bash. – Mad Physicist Jan 22 '22 at 20:11
1

The pathmunge function is already defined in /etc/profile:

pathmunge () {
    case ":${PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                PATH=$PATH:$1
            else
                PATH=$1:$PATH
            fi
    esac
}
Jack
  • 5,801
  • 1
  • 15
  • 20