35

I need to add a path in a bash script, but it may be executed several times:

export PATH=${OPENSHIFT_HOMEDIR}/app-root/runtime/bin/:${PATH}

I don't want that path to be added over and over. How can I add it if it is not in $PATH yet?

0

4 Answers 4

61

First check if the path to add is already part of the variable:

[[ ":$PATH:" != *":/path/to/add:"* ]] && PATH="/path/to/add:${PATH}"

If /path/to/add is already in the $PATH, then nothing happens, else it is added at the beginning.

If you need it at the end use PATH=${PATH}:/path/to/add instead.

Edit: In you case it would look like this:

[[ ":$PATH:" != *":${OPENSHIFT_HOMEDIR}/app-root/runtime/bin:"* ]] && PATH="${OPENSHIFT_HOMEDIR}/app-root/runtime/bin:${PATH}"
4
  • Can I write it like this? [[ ":$PATH:" != "${OPENSHIFT_HOMEDIR}/app-root/runtime/bin/" ]] && PATH="${OPENSHIFT_HOMEDIR}/app-root/runtime/bin/:${PATH}" ? Sorry, I am no expert with unix scripting... Jul 22, 2015 at 13:28
  • @JVerstry See my edited answer
    – chaos
    Jul 22, 2015 at 13:30
  • The colons before and after on both sides of the equals are for when adding a prefix of something already in PATH, e.g. adding '/home' when '/home/chaos/bin' is already present. Otherwise, the comparison would incorrectly say that '/home' was already present. Jan 7, 2021 at 13:42
  • 2
    It took me a minute to realize that this does indeed work even when the target path is the first or last in the $PATH. That's because you wrap the $PATH in colons before testing. Just thought I'd point that out in case anyone else pondered the same.
    – b-jazz
    Mar 28, 2021 at 16:26
27

The sysadmin in my old lab had a nifty little function for this:

pathmunge () {
        if ! echo "$PATH" | /bin/grep -Eq "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH="$PATH:$1"
           else
              PATH="$1:$PATH"
           fi
        fi
}

It will both check whether the string given is already in the PATH and also lets you add it to the end or the beginning as desired:

$ echo $PATH
/usr/local/bin:/usr/bin:/bin
$ pathmunge /sbin/             ## Add to the start; default
$ echo $PATH
/sbin/:/usr/local/bin:/usr/bin:/bin
$ pathmunge /usr/sbin/ after   ## Add to the end
$ echo $PATH
/sbin/:/usr/local/bin:/usr/bin:/bin:/usr/sbin/

I have this function in my ~/.profile and use it to modify my $PATH.

5
  • Wonder who's the original author of this particular function. It's kinda ubiquitous. Jul 22, 2015 at 19:19
  • @DeerHunter yeah, I've seen it around. All I know is that it's not mine and that my ex sysadmin gave it to me. Whether or not it's his is another matter :). It's pretty straightforward though, I'm sure many people have written this or a very similar approach independently.
    – terdon
    Jul 22, 2015 at 23:47
  • 4
    if using bash (v3.0 or later) may be cleaner to if [[ "${X}" =~ (^|:)${1}($|:) ]] ; ...
    – nhed
    Nov 13, 2017 at 21:09
  • Assume grep is on the path, since /bin/grep might not be universal installation path. Nov 13, 2021 at 2:44
  • @DarrenWeber if grep isn't in /bin/grep you can use the right path for it. But this is extremely unlikely, and I don't want to assume anything in the very function used to set up the PATH. That would defeat the purpose.
    – terdon
    Nov 13, 2021 at 12:43
4

If it's the same string, then just do it:

set -a -- "$OPENSHIFT_HOMEDIR/app-root/runtime/bin/"
PATH=$1:${PATH#"$1:"}
set +a --

You can do that over and over and the value of $PATH won't change.

Alternatively you can check for it.

set -a -- "$OPENSHIFT_HOMEDIR/app-root/runtime/bin/"
case :${PATH:=$1}: in
(*:"$1":*) ;; (*)
    PATH=$1:$PATH
esac;  set +a --
1

With GNU sed you can do it by

echo ${PATH} | 
    sed "\|${OPENSHIFT_HOMEDIR}/app-root/runtime/bin|\
        ! s|^|export PATH=${OPENSHIFT_HOMEDIR}/app-root/runtime/bin:|e"

Not the answer you're looking for? Browse other questions tagged or ask your own question.