Trevor Sears
Trevor Sears

Reputation: 539

zsh Looping through multiple parameters

In my old .bashrc, I had a short section as follows:

PATH2ADD_SCRIPTBIN="/home/foo/bar/scriptbin"
PATH2ADD_PYTHONSTUFF="/home/foo/bar/pythonprojects"

PATH2ADDLIST="$PATH2ADD_SCRIPTBIN $PATH2ADD_PYTHONSTUFF"

for PATH2ADD in $PATH2ADDLIST; do

    if [ -z `echo $PATH | grep "$PATH2ADD"` ]; then

        export PATH=$PATH:$PATH2ADD
        echo "Added '$PATH2ADD' to the PATH."

    fi

done

And in Bash, this worked just as intended: it appended the paths I included in $PATH2ADDLIST if they were not already present in the path (I had to do this after realizing how huge my path was getting each time I was sourcing my .bashrc). The output (when the provided paths were not already present) was as follows:

Added '/home/foo/bar/scriptbin' to the PATH.
Added '/home/foo/bar/pythonprojects' to the PATH.

However, I recently switched over to the magical land of Zsh, and the exact same lines of text now produce this result:

Added '/home/foo/bar/scriptbin /home/foo/bar/pythonprojects' to the PATH.

Now I'm pretty sure that this is because of some difference in how Zsh does parameter expansion, or that it has something to do with how Zsh changes the for loop, but I'm not really sure how to fix this.

Might anyone have some insight?

Upvotes: 2

Views: 1287

Answers (2)

chepner
chepner

Reputation: 532538

zsh has a few features that make it much easier to update your path. One, there is an array parameter path that mirrors PATH: a change to either is reflected in the other. Two, that variable is declared to eliminate duplicates. You can simply write

path+=("/home/foo/bar/scriptbin" "/home/foo/bar/pythonprojects")

and each new path will be appended to path if it is not already present.

If you want more control over the order in which they are added (for example, if you want to prepend), you can use the following style:

path=( "/home/foo/bar/scriptbin"
        $path
       "/home/foo/bar/pythonprojects"
)

(Note that the expansion of an array parameter includes all the elements, not just the first as in bash.)

Upvotes: 2

Inian
Inian

Reputation: 85895

Use an array to store those variables, i.e.

PATH2ADD_SCRIPTBIN="/home/foo/bar/scriptbin"
PATH2ADD_PYTHONSTUFF="/home/foo/bar/pythonprojects"

# Initializing 'PATH2ADDLIST' as an array with the 2 variables
# to make the looping easier

PATH2ADDLIST=("${PATH2ADD_SCRIPTBIN}" "${PATH2ADD_PYTHONSTUFF}")

# Looping through the array contents
for PATH2ADD in "${PATH2ADDLIST[@]}"
do 
    # Using the exit code of 'grep' directly with a '!' negate
    # condition
    if ! echo "$PATH" |  grep -q "$PATH2ADD"
    then
        export PATH=$PATH:$PATH2ADD
        echo "Added '$PATH2ADD' to the PATH."
    fi
done

This way it makes it more compatible in both zsh and bash. A sample dry run on both the shells,

# With interpreter set to /bin/zsh

zsh script.sh 
Added '/home/foo/bar/scriptbin' to the PATH.
Added '/home/foo/bar/pythonprojects' to the PATH.

and in bash

bash script.sh 
Added '/home/foo/bar/scriptbin' to the PATH.
Added '/home/foo/bar/pythonprojects' to the PATH.

Upvotes: 3

Related Questions