Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Bash: testing a variable

2 views
Skip to first unread message

Charles Curley

unread,
Jul 9, 2021, 4:00:05 PM7/9/21
to
I'd like to check two things:

* Whether a given path is not already in the $PATH variable

* Whether the given path already exists

If both are true, I'd like to add the given path to the $PATH variable.

I can add the given path, and test for the existence of the given path.
I can write expressions that work to detect the given path in $PATH.
What I don't seem able to do is combine all that in a script.

Here's what I have for the script:

#!/bin/bash

# A short script for testing some code.

# pelican seems to like local installations here.
SUBSTR="${HOME}"/\.local/bin/
echo Substr is "${SUBSTR}"
# if [[ ! ${PATH} =~ .*/home/charles/.local/bin.* ]] ; then
if [[ $( echo "$PATH" | grep -E -v "${SUBSTR}" ) ]] ; then
echo Substring NOT found.;

if [ -d "${HOME}/.local/bin/" ] ; then
echo Adding to \$PATH
PATH=${HOME}/.local/bin:$PATH
fi
else
echo Substring found!;
fi

I call the script with the . operator: ". test.sh"

Why do I always end up adding the given path, even if it is already in
$PATH?

Debian is Buster, bash is 5.0.3(1)-release (x86_64-pc-linux-gnu).

--
Does anybody read signatures any more?

https://charlescurley.com
https://charlescurley.com/blog/

Joerg Kampmann

unread,
Jul 9, 2021, 4:20:04 PM7/9/21
to

Am 09.07.21 um 21:54 schrieb Charles Curley:
> I'd like to check two things:
>
> * Whether a given path is not already in the $PATH variable
>
> * Whether the given path already exists
>
> If both are true, I'd like to add the given path to the $PATH variable.
>
> I can add the given path, and test for the existence of the given path.
> I can write expressions that work to detect the given path in $PATH.
> What I don't seem able to do is combine all that in a script.
>
> Here's what I have for the script:
>
> #!/bin/bash
>
> # A short script for testing some code.
>
> # pelican seems to like local installations here.
> SUBSTR="${HOME}"/\.local/bin/
> echo Substr is "${SUBSTR}"
> # if [[ ! ${PATH} =~ .*/home/charles/.local/bin.* ]] ; then
> if [[ $( echo "$PATH" | grep -E -v "${SUBSTR}" ) ]] ; then
> echo Substring NOT found.;
>
> if [ -d "${HOME}/.local/bin/" ] ; then
> echo Adding to \$PATH
> PATH=${HOME}/.local/bin:$PATH
> fi
> else
> echo Substring found!;
> fi
>
> I call the script with the . operator: ". test.sh"
this is the result:


root@primergy:~/software-env# . test.sh

Substr is /root/.local/bin/
Substring NOT found.
root@primergy:~/software-env#

Greg Wooledge

unread,
Jul 9, 2021, 4:30:04 PM7/9/21
to
On Fri, Jul 09, 2021 at 01:54:19PM -0600, Charles Curley wrote:
> I'd like to check two things:
>
> * Whether a given path is not already in the $PATH variable
>
> * Whether the given path already exists
>
> If both are true, I'd like to add the given path to the $PATH variable.

add_path_maybe() {
local p i

if [[ $1 != /* ]]; then
echo "refusing to consider a directory that doesn't begin with /" >&2
return 1
fi

if [[ ! -d $1 ]]; then
echo "directory '$1' does not exist" >&2
return 1
fi

IFS=: read -ra p <<< "$PATH"
for i in "${p[@]}"; do
if [[ $i = "$1" ]]; then
return 0
fi
done

PATH=$PATH:$1
}

Kampmann

unread,
Jul 9, 2021, 4:40:04 PM7/9/21
to

I am sorry I found myself in the wrong thread ... so discard

Am 09.07.21 um 22:25 schrieb Greg Wooledge:
-- 
=============================================================================
Joerg Kampmann, Dr. Dipl.-Phys - IBK-Consult for Climate Physics - non-profit - 
D-31228 Peine +49-177-276-3140
www.ibk-consult.de - www.kampmannpeine.org
www.xing.com/hp/Joerg_Kampmann
www.xing.com/net/mathe
www.researchgate.net/profile/Joerg_Kampmann - https://independent.academia.edu/J%C3%B6rgKampmann
===============================================================================
This e-mail may contain confidential and/or legally protected information.
If you are not the intended recipient (or have received this e-mail in
error) please notify the sender immediately and delete this e-mail. Any
unauthorized copying, disclosure use or distribution of the material in
this e-mail is strictly forbidden.
Diese E-Mail enthält vertrauliche und/oder rechtlich geschuetzte Informationen.
Wenn Sie nicht der richtige Adressat sind oder diese E-Mail irrtuemlich
erhalten haben, informieren Sie bitte sofort den Absender und loeschen
Sie diese Mail
===============================================================================

Charles Curley

unread,
Jul 9, 2021, 4:50:05 PM7/9/21
to
On Fri, 9 Jul 2021 16:25:11 -0400
Greg Wooledge <gr...@wooledge.org> wrote:

> add_path_maybe() {
> local p i
> ...

Very nice, sir. Thank you.

shellcheck complained about the redirection in the "IFS=: read" line,
but I'm not going to worry about that.

Charles Curley

unread,
Jul 9, 2021, 4:50:05 PM7/9/21
to
On Fri, 9 Jul 2021 22:11:05 +0200
Joerg Kampmann <ibk-klim...@ibk-consult.de> wrote:

> > I call the script with the . operator: ". test.sh"
> this is the result:
>
>
> root@primergy:~/software-env# . test.sh
>
> Substr is /root/.local/bin/
> Substring NOT found.
> root@primergy:~/software-env#

OK, that's what I get if I don't have ~/.local/bin.

charles@white:~$ . test.sh
Substr is /home/charles/.local/bin/. $PATH is /home/charles/bin:/home/charles/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games.
Substring NOT found.
$PATH is /home/charles/bin:/home/charles/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games.
charles@white:~$

(I added the code to print out $PATH at the end.)

Now, is ~/.local/bin present on your computer? It is not present on
white, above. If not, what happens if you create it and then run
test.sh? (mkdir -p ~/.local/bin)?

Greg Wooledge

unread,
Jul 9, 2021, 5:00:04 PM7/9/21
to
On Fri, Jul 09, 2021 at 02:45:23PM -0600, Charles Curley wrote:
> On Fri, 9 Jul 2021 16:25:11 -0400
> Greg Wooledge <gr...@wooledge.org> wrote:
>
> > add_path_maybe() {
> > local p i
> > ...
>
> Very nice, sir. Thank you.
>
> shellcheck complained about the redirection in the "IFS=: read" line,
> but I'm not going to worry about that.

Since it's a function, and not a script, there's no shebang. So I'm
guessing shellcheck assumed it was /bin/sh code, rather than bash code.
<<< is just one of the bashisms I used here. local is another. The
use of arrays is a third. The [[ command is a fourth.

The traditional way of doing this in sh involves pattern-matching
:$PATH: against *:/your/dir:* instead of splitting the PATH into array
elements and iterating over them. It's an ugly hack, which is basically
what you always have to do in sh, because it lacks so many features.

john doe

unread,
Jul 9, 2021, 5:50:04 PM7/9/21
to
On 7/9/2021 9:54 PM, Charles Curley wrote:
> I'd like to check two things:
>
> * Whether a given path is not already in the $PATH variable
>
> * Whether the given path already exists
>
> If both are true, I'd like to add the given path to the $PATH variable.
>
> I can add the given path, and test for the existence of the given path.
> I can write expressions that work to detect the given path in $PATH.
> What I don't seem able to do is combine all that in a script.
>
> Here's what I have for the script:
>
> #!/bin/bash
>
> # A short script for testing some code.
>
> # pelican seems to like local installations here.
> SUBSTR="${HOME}"/\.local/bin/
> echo Substr is "${SUBSTR}"
> # if [[ ! ${PATH} =~ .*/home/charles/.local/bin.* ]] ; then

[[ $PATH =~ \/home\/charles\/... ]] && echo match || echo nomatch

That is, escaping the backslash.

> if [[ $( echo "$PATH" | grep -E -v "${SUBSTR}" ) ]] ; then

Try the -q opt to grep or redirecting the output to the null device:

'if $(echo $PATH | grep -v $SUBSTR 2>&1); then'

> I call the script with the . operator: ". test.sh"
>

Personally, I would invoke the script as './try.sh' and use sourcing
('source, '.') to include libraries...
I would also not use 'test' as a name for a script (could be confused
with the test command).

> Why do I always end up adding the given path, even if it is already in
> $PATH?
>

Because if there is a match, grep will print the value of the match (in
this case the content of $PATH).
So the condition will always be 0.

--
John Doe

Greg Wooledge

unread,
Jul 9, 2021, 6:10:04 PM7/9/21
to
On Fri, Jul 09, 2021 at 11:40:36PM +0200, john doe wrote:
> On 7/9/2021 9:54 PM, Charles Curley wrote:
> > # if [[ ! ${PATH} =~ .*/home/charles/.local/bin.* ]] ; then
>
> [[ $PATH =~ \/home\/charles\/... ]] && echo match || echo nomatch
>
> That is, escaping the backslash.

First, you are escaping forward slashes, *using* backslashes.

Second, you don't need to escape slashes. They aren't special in an ERE.

Third, you *do* need to escape the dots. Those *are* special in an ERE.

Fourth, you don't actually need an ERE here. For a simple substring
match, you can just use [[ $PATH != *substring* ]]

But as I said in a different message, if you're going down this road
(which is more typical for sh than for bash), you will want to delimit
both the left-hand and right-hand sides with extra : characters.

Without those, you will get false positives. For example, if your PATH
contains /usr/bin and you try to check whether it contains /bin, you'll
get a match, because /bin is literally part of the /usr/bin component.

Anyway, that's why I called that an ugly hack.

Charles Curley

unread,
Jul 9, 2021, 8:20:05 PM7/9/21
to
On Fri, 9 Jul 2021 16:53:45 -0400
Greg Wooledge <gr...@wooledge.org> wrote:

> Since it's a function, and not a script, there's no shebang. So I'm
> guessing shellcheck assumed it was /bin/sh code, rather than bash
> code. <<< is just one of the bashisms I used here. local is
> another. The use of arrays is a third. The [[ command is a fourth.

I had dropped the function into a script, and added code to use it, and
a shebang. So shellcheck knew to allow bashisms. Why it didn't like that
one I don't know.
0 new messages