10

I need to append a directory to PKG_CONFIG_PATH. Normally, I would use the standard

export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:$(pyenv prefix)/lib/pkgconfig

but PKG_CONFIG_PATH has not been previously set on my system. Therefore, the variable begins with a : character, which tells it to look in the current directory first. I do not want that. I settled on the following,

export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}${PKG_CONFIG_PATH:+:}$(pyenv prefix)/lib/pkgconfig

but that just seems so ugly. Is there a better way? What is the appropriate way to conditionally append the colon if and only if the variable has already been set?

12

You are on the right track with the ${:+} expansion operator, you just need to modify it slightly:

V=${V:+${V}:}new_V

The first braces expand to $V and the colon iff V is set already otherwise to nothing - which is exactly what you need (and probably also one of the reasons for the existence of the operator).

Thus in your case:

export "PKG_CONFIG_PATH=${PKG_CONFIG_PATH:+${PKG_CONFIG_PATH}:}$(pyenv prefix)/lib/pkgconfig"
  • I was using that form, but I decided against it because it felt (slightly) less readable: ${V}${V:+:}W vs. ${V:+${V}:}W. Either way, they both feel really ugly. I was hoping for something... more elegant, I guess? – scottbb Oct 18 '14 at 20:06
  • @scottbb - this is the syntax form - it is how it is done. If you want to set a variable's value based on a condition you have to do a test. You can do an inline test as is written here, or you can explicitly test with test - either way you're testing the value and writing the varname twice, but this way you do it in a single execution statement - in that way it is practical, but I've never met an elegant computer. – mikeserv Oct 18 '14 at 20:18
  • @scottbb Thinking of it it really is the same. But I'm afraid you won't get it any better, since you basically need the variable name in the condition and then in the expansion - I don't think there is a shell construct that would do that with just one occurrence of the name. – peterph Oct 18 '14 at 20:23
  • @mikeserv - I probably should have been more precise than to say I was looking for a more "elegant" solution. I have never really seen this done for appending substrings to PATH-style variables, and it felt somehow like I was missing a better way. In my experience, when I get that feeling, there usually is a better way. That's what I should have said. But your point is well taken. Thanks for your response. Also: in one of your edits of @peterph's comment, you made the comment that I should have quoted the entire argument to export. That's a very good point, I miffed that detail as well. – scottbb Oct 18 '14 at 21:27
  • @scottbb - sorry if that came off as abrasive - ive never understood the concept of elegance with regards to computing. a computer is a machine - a three-way and/or gate compounded billions of times. it cant count higher than one - in every way, every thing it does is brute-forced. some intuitive concepts may be easier to translate than others, but, if so, it is only because the concept sits atop some other brute-forced abstraction. computing, at its heart, is always anything but elegant. – mikeserv Oct 18 '14 at 21:41
1

Lately, I set up GNU stow on my machines to store user-wide stuff like libraries under ~/.local and ran into troubles when defining LD_LIBRARY_PATH, CPATH and LIBRARY_PATH, inadvertently putting a colon there and so breaking stuff.

Then I found your question and the answer wasn't exactly elegant ;-), and I wrote a small function to handle this, please find it here: https://gist.github.com/rico-chet/0229e4c080d9f51a02535dd25a656a8a

## Copyright (C) 2018 Alex Thiessen <alex.thiessen.de+github@gmail.com>
## Copyright (C) 2018 https://unix.stackexchange.com/users/116858/kusalananda
## SPDX-License-Identifier: GPL-2.0-or-later
## <https://spdx.org/licenses/GPL-2.0-or-later.html>

function join() {
    if [ ${#} -eq 0 ]
    then
        echo "\`join\` appends elements separated by colons to a \`bash\` variable " >&2
        echo "usage: join <variable> <element> [element ...]" >&2
        return 1
    fi
    variable="${1}"

    shift
    export ${variable}="${!variable:+${!variable}:}$(IFS=:; echo "${*}")"
}

// edited as suggested by @Kusalananda

  • Also: ( IFS=:; set -- 1 2 3 4 5 6; echo "$*" ) – Kusalananda Jul 22 '18 at 11:49
  • I.e.: join () { var=$1; shift; export "$var"="$( IFS=:; echo "$*" )"; } – Kusalananda Jul 22 '18 at 12:37
  • ... Except that "join" is an unfortunate name as its also the name of a standard utility. – Kusalananda Jul 22 '18 at 13:11
  • Nice one, except for the fact that you'd overwrite the variable instead of appending to it. Just adding ${!variable:+${!variable}:} at the right place worked for me, all tests passed. Finding an appropriate name is an exersize to the reader :) – Superlexx Sep 13 '18 at 23:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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