What is this $PATH in Linux and how to modify it - linux

I have a few questions on this $PATH in Linux.
I know it tells the shell which directories to search for executable files, so:
What does it mean an environmental variable?
How to change its path? and is it recommended to change it?
IF i change it what are the consequences?

To get your path current $PATH variable type in:
echo $PATH
It tells your shell where to look for binaries.
Yes, you can change it - for example add to the $PATH folder with your custom scripts.
So: if your scripts are in /usr/local/myscripts to execute them you will have to type in a full path to the script: /usr/local/myscripts/myscript.sh
After changing your $PATH variable you can just type in myscript.sh to execute script.
Here is an example of $PATH from RHEL:
/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/user/bin
To change your $PATH you have to either edit ~/.profile (or ~/.bash_profile) for user or global $PATH setting in /etc/profile.
One of the consequences of having inaccurate $PATH variables is that shell will not be able to find and execute programs without a full $PATH.

Firstly, you are correct in your statement of what $PATH does. If you were to break it somehow (as per your third point), you will have to manually type in /usr/bin/xyz if you want to run a program in /usr/bin from the terminal. Depending on how individual programs work, this might break some programs that invoke other ones, as they will expect to just be able to run ls or something.
So if you were to play around with $PATH, I would suggest saving it somewhere first. Use the command line instruction
echo $PATH > someRandomFile.txt
to save it in someRandomFile.txt
You can change $PATH using the export command. So
export PATH=someNewPath
HOWEVER, this will completely replace $PATH with someNewPath. Since items in path are separated by a ":", you can add items to it (best not to remove, see above) by executing
export PATH=$PATH:newPath
The fact that it is an environmental variable means that programs can find out its value, ie it is something that is set about the environment that the program is running in. Other environmental variables include things like the current directory and the address of the current proxy.

this is simple and i do like this way.
Open the linux bash shell and print the environment variables:
printenv
I copy "PATH" variable to a text editor and edit as I want. Then update the PATH like this
export PATH= /variable dir list/
It Works.
or if you want to add an single variable use this command.
export PATH = $PATH:/variable_dir_path/
This will extends the PATH with your new directory path.

Related

Android Studio - cmake - access environement variable?

This question is specific to using cmake as part of Android Studio build process.
I'm using Android Studio 2.2 preview 7 on linux (ubuntu)
Inside the CMakeLists.txt I am able to access the Android NDK path using: ${ANDROID_NDK}
But how can I access:
Any environment variable ?
If not possible, at least the Android SDK path ?
I already tried to used $ENV{name_of_the_environment_variable_here} but it's always empty, even if the environment variable exist. I guess that when gradle invoke cmake it "hide" the env var somehow.
I don't think you can use $ENV, it's just an example of a variable because they're environment variables. However, you should be able to type env and hit enter for a list of the variables you currently have set. Then, the ones you see in the list, you can invoke by typing $VARIABLE_NAME, using a command before them to get them to do something. E.g. echo $VARIABLE will echo your variable to stdout.
I'm not sure how $ANDROID_SDK was set, if it was part of an install process, etc. but generally you would set user environment variables in .profile, .bash_profile or .bashrc configuration files. These files are read by the shell in that order. System-wide variables are set in /etc/environment, /etc/profile, and /etc/bash.bashrc, but you probably don't want to mess with those (most distros encourage making ancillary additions in /etc/profile.local, but that's a story for another answer).
It doesn't particularly matter which one of these files you use, unless what you're trying to do interacts with the order in which they are loaded. Generally, I look for where the variables have been set by either the OS or other stuff I've added and put them near those. You can find where environment variables are set by typing:
% for i in .profile .bash_profile .bashrc; do grep -H PATH $HOME/$i; done
(% is the prompt, don't type %)
.. and this will loop through the 3 files and show you if a user $PATH is set in any of them.
Bash uses the export ENV command as opposed to set ENV, which is from the original sh, which AFAIK is only default on FreeBSD and derivatives like pfSense anymore. Almost all other OS use Bash by default, except MacOS which recently moved to zsh and also uses export, and OpenBSD which uses ksh (nobody uses OpenBSD).
If you want to verify which shell you are using, type echo $SHELL, or echo $0 and hit enter, and it should let you know.
You can add the environment variable ephemerally by typing this command in your bash terminal and pressing enter:
% export ANDROID_SDK_ROOT=/home/username/AndroidSDK
To be clear, this is an example path, so it'd be best to use the actual path in which your android SDK files reside. However, this example was a default install location Android Studio tried to use when I installed it recently, so if you're not sure where they are, it's probably a good place to check.
To have a more permanent setting of your environment variable, open a text editor and add the line above to one of the configuration files I mentioned in the first paragraph (they'll be in your $HOME folder). Or, you can run this from the prompt and it'll add it to your file automatically:
% echo 'export ANDROID_SDK_ROOT=/home/username/AndroidSDK' >> $HOME/.bashrc
Take care to use two angle brackets and not one, as one angle bracket will overwrite the entire file with the single line.
How can I access Any environment variable ?
If you're not sure which folder is $HOME, try typing cd $HOME and hitting enter - that'll take you there. That's how you access environment variables - use a command with the invocation of the variable and it should act as if you had typed out the entire thing.
To access environment variables, type echo $NAME_OF_VARIABLE and it should echo it to the screen. If you want to search your three config files I mentioned in the beginning for where an environment variable is set, you can use grep as I did earlier, just changing the search string for whatever you're looking for. E.g. (while in $HOME):
% grep SDK_ROOT .bashrc .profile .bash_profile
Or you can type env to list all the currently set variables and filter them by piping the output to the grep command:
% env | grep SDK
If you want to just list all of the set variables and root around the entire thing, just type env instead of piping it to grep (grep's a filter).
Lastly, I'll give you an example of my $ANDROID_SDK_ROOT $ANDROID_SDK and $SDK_ROOT variables in my .bashrc - I noticed while installing these tools, they use all three (isn't that fun?):
% grep ANDROID .bashrc
export ANDROID_SDK=$HOME/development/Android/SDK
export ANDROID_SDK_ROOT=$HOME/development/Android/SDK
export PATH=$PATH:$ANDROID_SDK:$JAVA_HOME:$ANDROID_SDK/cmdline-tools/latest/bin:$ANDROID_SDK/build-tools/32.0.0:$ANDROID_SDK/emulator:$ANDROID_SDK/emulator/bin64:$ANDROID_SDK/tools:$ANDROID_SDK/tools/bin:$ANDROID_SDK/extras:$ANDROID_SDK/platform-tools:$HOME/development/AndroidStudio/bin
export ANDROID_STUDIO=$HOME/development/AndroidStudio
% grep SDK_ROOT .bashrc
export SDK_ROOT=$HOME/development/Android/SDK
export ANDROID_SDK_ROOT=$HOME/development/Android/SDK
Hope that answers some questions, sorry it took so long to give you a response.

Import PATH environment variable into Bash script launched with cron

When creating Bash scripts, I have always had a line right at the start defining the PATH environment variable. I recently discovered that this doesn't make the script very portable as the PATH variable is different for different versions of Linux (in my case, I moved the script from Arch Linux to Ubuntu and received errors as various executables weren't in the same places).
Is it possible to copy the PATH environment variable defined by the login shell into the current Bash script?
EDIT:
I see that my question has caused some confusion resulting in some thinking that I want to change the PATH environment variable of the login shell with a bash script, which is the exact opposite of what I want.
This is what I currently have at the top of one of my Bash scripts:
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
# Test if an internet connection is present
wget -O /dev/null google.com
I want to replace that second line with something that copies the value of PATH from the login shell into the script environment:
#!/bin/bash
PATH=$(command that copies value of PATH from login shell)
# Test if an internet connection is present
wget -O /dev/null google.com
EDIT 2: Sorry for the big omission on my part. I forgot to mention that the scripts in question are being run on a schedule through cron. Cron creates it's own environment for running the scripts which does not use the environment variables of the login shell or modify them. I just tried running the following script in cron:
#!/bin/bash
echo $PATH >> /home/user/output.txt
The result is as follows. As you can see, the PATH variable used by cron is different to the login shell:
user#ubuntu_router:~$ cat output.txt
/usr/bin:/bin
user#ubuntu_router:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
Don't touch the user's PATH at all unless you have a specific reason. Not doing anything will (basically) accomplish what you ask.
You don't have to do anything to get the user's normal PATH since every process inherits the PATH and all other environment variables automatically.
If you need to add something nonstandard to the PATH, the usual approach is to prepend (or append) the new directory to the user's existing PATH, like so:
PATH=/opt/your/random/dir:$PATH
The environment of cron jobs is pretty close to the system's "default" (for some definition of "default") though interactive shells may generally run with a less constrained environment. But again, the fix for that is to add any missing directories to the current value at the beginning of the script. Adding directories which don't exist on this particular system is harmless, as is introducing duplicate directories.
I've managed to find the answer to my question:
PATH=$PATH:$(sed -n '/PATH=/s/^.*=// ; s/\"//gp' '/etc/environment')
This command will grab the value assigned to PATH by Linux from the environment file and append it to the PATH used by Cron.
I used the following resources to help find the answer:
How to grep for contents after pattern?
https://help.ubuntu.com/community/EnvironmentVariables#System-wide_environment_variables

turning on / off environment variables

I have been trying to set the $PATH environment variable to point to different paths as I need them, but I have run into some issues.
The main thing is that when I set the PATH to point to my service that I need, I want it to stay that way in all subsequent bash shells. That is, when I open another bash shell it will be set there as well, until I decide to switch it back. And when I switch the PATH back to its original value. I want it to stay that way.
I added a small script to my .bashrc, I also tried doing a separate script that will change environment variables. But the problem stays: If I open a new bash shell, it inherits the default environment variables and the default PATH.
I am setting those to enable the use of a daemon service. I tried turning on/off the service itself. That does not work because the paths have to be changed or else the shell would try to use those environment paths, but the service being off it will just hang.
I tried running a small C program wrapper to do those things but I ran into the same issue.
In order for environment variable to exist across shell sessions you will need to place those variables into a shell configuration file. This is usually done in either ~/.bashrc or ~/.profile (if you are using Bash). For example, in my ~/.profile file I have:
export PATH=/opt/local/bin:/opt/local/sbin:$PATH
I can add to that path as much as I want. The $PATH variable at the end will append whatever is current in the path.
If you need scripts to be able to access the variables, you should put the PATH into the .bashrc file. (what is the difference between .bashrc and .profile)
If you make a change to one of your shell configuration files, the changes will not be in effect until those files are used again. Those files are only used when the shell is first initialized. In order to make changes take effect, you need to log out and back in, or open a new shell and close the old, or source the file that you made changes to.
$ vim ~/.bashrc (edit the file)
$ source ~/.bashrc (then reinitialize the shell with the file)
If you only need a variable to be available in the current shell and any subprocesses, using export would be all you need.
You might also be interested in this snippet. It reloads the .bashrc in any shell, whenever it is modified. (After re-editing the .bashrc file, press (or run a command) to cause the new .bashrc to be reloaded.)
# Make sure our version of the .bashrc file is up-to-date, or reload it.
chk_bashrc_timestamp () {
if [[ "$_BASHRC_TIMESTAMP" -lt "$(get_file_timestamp "$HOME/.bashrc")" ]]; then
echo >&2 "Reloading .bashrc..."
. ~/.bashrc
fi
}
_BASHRC_TIMESTAMP=$(date +%s)
PROMPT_COMMAND=chk_bashrc_timestamp
The only difficulty is, you must not use $PATH in the definition of PATH, or it will repeat the whole PATH each time it is needed:
Use
SYSPATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
PATH="$HOME/bin:$SYSPATH:/opt/mystuff"
instead of
PATH="$HOME/bin:$PATH:/opt/mystuff"
I have used this with much satisfaction in my own .bashrc, except that I have protected my PATH from reloading each time by setting it in an if statement. (You may find you have other things you need to protect this way.)
if _BASHRC_WAS_RUN 2>/dev/null; then
:;
else # Stuff that only needs to run the first time we source .bashrc.
# Useful to allow resourcing new changes
export PATH="$HOME/bin:$HOME/.cabal/bin: ..."
alias _BASHRC_WAS_RUN=true
fi

When I execute bash, the $PATH keeps repeating itself

I have added entries such as the following in my /etc/bashrc (on Fedora).
#=========== Maven Related variables
export JAVA_HOME='/usr/java/default'
export PATH=${JAVA_HOME}:$PATH
#=========== Maven Related variables
export M2_HOME=/usr/local/apache-maven/apache-maven-3.0.4
export PATH=${M2_HOME}/bin:$PATH
#=========== Ant Related variables
export ANT_HOME=/usr/local/apache-ant
export Path=${ANT_HOME}/bin:$PATH
Now, each time that I execute bash command to refresh the environment variables, all these additions are repeated, and the PATH just keep adding itself recursively; if I keep doing bash for a few dozen times, then the $PATH becomes a hundred lines of repeating content. What am I doing wrong?
Note that I have added these entries to /etc/bashrc since I want to have these values in PATH no matter what user I login as.
Thanks,
Shannon
Don't set your PATH incrementally in .bashrc; set it once in .profile and leave it alone thereafter. Or, since you mention /etc/bashrc, don't set the PATH incrementally in /etc/bashrc; set it once in /etc/profile and leave it alone.
One side-benefit; things will work a little faster.
See also the code in How do I manipulate PATH elements in shell scripts for code to clean up a repetitive PATH.
If by this statement:
... execute bash command to refresh the environment variables ...
you mean that you are entering the command
bash
at the command prompt, you are not "refreshing the environment variables". You are launching a new subshell of the current shell. The new shell inherits the path of the original shell, to which you are once again making additions. Each time you do this the PATH will get longer.
You can use something like:
PATH=$(echo "$PATH" | awk -v RS=: -v ORS=: '!(a[$0]++)' | sed 's/:$//')
to clean up your path after changing it. Also, since the the first match is used when scanning the path, having duplicates doesn't really matter.
I had also faced the same problem (CentOS). This is how I fixed it.
Added the following lines to my user's .profile
export PATH=/usr/local/apache-maven-3.3.3/bin:$PATH
export JAVA_HOME=/usr
export SHELL=/bin/bash
# to run bash (because ksh was my default shell)
/bin/bash
No changes to my user's .bashrc file
No changes to /etc/profile
No changes to /etc/bashrc

Adding a new entry to the PATH variable in ZSH

I'm using zsh terminal, and I'm trying to add a new entry (/home/david/pear/bin) to the PATH variable. I don't see a reference to the PATH variable in my ~/.zshrc file, but doing echo $PATH returns:
/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
So I know that the path variable is being set somewhere. Where is the PATH variable set / modified for the zsh terminal?
Actually, using ZSH allows you to use special mapping of environment variables. So you can simply do:
# append
path+=('/home/david/pear/bin')
# or prepend
path=('/home/david/pear/bin' $path)
# export to sub-processes (make it inherited by child processes)
export PATH
For me that's a very neat feature which can be propagated to other variables.
Example:
typeset -T LD_LIBRARY_PATH ld_library_path :
Here, add this line to .zshrc:
export PATH=/home/david/pear/bin:$PATH
EDIT: This does work, but ony's answer above is better, as it takes advantage of the structured interface ZSH provides for variables like $PATH. This approach is standard for bash, but as far as I know, there is no reason to use it when ZSH provides better alternatives.
You can append to your PATH in a minimal fashion. No need for
parentheses unless you're appending more than one element. It also
usually doesn't need quotes. So the simple, short way to append is:
path+=/some/new/bin/dir
This lower-case syntax is using path as an array, yet also
affects its upper-case partner equivalent, PATH (to which it is
"bound" via typeset).
(Notice that no : is needed/wanted as a separator.)
Common interactive usage
Then the common pattern for testing a new script/executable becomes:
path+=$PWD/.
# or
path+=$PWD/bin
Common config usage
You can sprinkle path settings around your .zshrc (as above) and it will naturally lead to the earlier listed settings taking precedence (though you may occasionally still want to use the "prepend" form path=(/some/new/bin/dir $path)).
Related tidbits
Treating path this way (as an array) also means: no need to do a
rehash to get the newly pathed commands to be found.
Also take a look at vared path as a dynamic way to edit path
(and other things).
You may only be interested in path for this question, but since
we're talking about exports and arrays, note that
arrays generally cannot be exported.
You can even prevent PATH from taking on duplicate entries
(refer to
this
and this):
typeset -U path
PATH pre-populated
The reason your path already has some entries in it is due to your system shell files setting path for you. This is covered in a couple other posts:
Why and where the $PATH env variable is set?
Where is the source of $PATH? I cannot find it in .zshrc
one liner, without opening ~/.zshrc file
echo -n 'export PATH=~/bin:$PATH' >> ~/.zshrc
or
echo -n 'export PATH=$HOME/bin:$PATH' >> ~/.zshrc
To see the effect, do source ~/.zshrc in the same tab or open a new tab
Added path to ~/.zshrc
sudo vi ~/.zshrc
add new path
export PATH="$PATH:[NEW_DIRECTORY]/bin"
Update ~/.zshrc
Save ~/.zshrc
source ~/.zshrc
Check PATH
echo $PATH
OPTION 1: Add this line to ~/.zshrc:
export "PATH=$HOME/pear/bin:$PATH"
After that you need to run source ~/.zshrc in order your changes to take affect OR close this window and open a new one
OPTION 2: execute it inside the terminal console to add this path only to the current terminal window session. When you close the window/session, it will be lost.
If you are on macOS (I'm on Monterey 12.3.1), you may have been pulling your hair like I did metaphorically. These instructions above all worked for me within the terminal session, but I could never get it to persist no matter what I did with export. Moreover, I couldn't find the .zshrc anywhere.
Turns out Apple does it differently. The file you need to edit is etc/paths. You can simply sudo nano /etc/paths and add your path in a new line. Then simply restart terminal and voila.
for me PATH=$PATH:/path/to/file/bin
then export PATH worked.
to check echo $PATH . other solutions are adding the path temporarily.
I'm on Monterey 12.4 and the only way I could change the path was using the helper function. Editing text files in nano did diddly squat
# append
path+=('/foo/bar/yourpath')
# export to sub-processes
export PATH
to verify your new directory has been added correctly, you can use
print -l $path
thanks to the fact that its type is known to be an array

Resources