2

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?

6
  • zsh breaks from the POSIX standard to prevent word-splitting on parameter expansions by default. You can re-enable that with setopt SH_WORD_SPLIT. Commented Feb 6, 2017 at 15:20
  • zsh is not bash -- nor is the language it implements a compatible superset of bash. Do not use the bash tag for zsh questions. Commented Feb 6, 2017 at 15:26
  • (that said -- in both shells, setting a shell variable with the same name as a preexisting environment variable overwrites the latter. This makes the POSIX standard's specification that all-uppercase names are used for variables with meaning to the system or shell, whereas lowercase names are reserved for application use, pertinent). Commented Feb 6, 2017 at 15:29
  • @CharlesDuffy my question was relevant to the differences between Bash and Zsh... the question did not solely relate to Zsh. The point wasn't just to solve a problem with a script, it was also to further understanding of the differences. Just seeking information! :) Commented Feb 6, 2017 at 17:36
  • @TrevorSears, the thing to keep in mind when tagging is "what kind of expertise is required for someone to answer this question?". Someone who knows bash but not zsh won't be of any help here; someone who knows zsh but not bash will be fine (particularly if they know how zsh differs from the POSIX sh specification or closer ksh88 derivatives -- pretty much mandatory knowledge to be able to port scripts to/from zsh or write code compatible between zsh and other shells). Commented Feb 6, 2017 at 22:06

2 Answers 2

3

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. 
Sign up to request clarification or add additional context in comments.

5 Comments

Awesome, this works wonderfully! What does the [@] do in "${PATH2ADDLIST[@]}" though?
"${PATH2ADDLIST[@]}" represents the entire contents of the array, we are using a loop to process one entry at a time!
Ah, ok. Thanks for the info!
@TrevorSears: Happy to help!
@TrevorSears Note that this is how you should have done it in bash as well.
2

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.)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.