This question already has answers here:
How to permanently set $PATH on Linux/Unix [closed]
(24 answers)
Closed 6 years ago.
This is a very interesting question that I stumbled upon when I was creating a command-line application tool for Linux. Unfortunately, the answer on SO is so hidden among the myriad answers to other questions that I decided to ask another question on SO for those who want to modify PATH programmatically.
Grzegorz Żur's answer to another question captures it brilliantly. Unfortunately it was hidden away among many other answers.
There are multiple ways to do it. The actual solution depends on the
purpose.
The variable values are usually stored in either a list of assignments
or a shell script that is run at the start of the system or user
session. In case of the shell script you must use a specific shell
syntax.
System wide
/etc/environment List of unique assignments. Perfect for adding system-wide directories like /usr/local/something/bin to PATH
variable or defining JAVA_HOME.
/etc/xprofile Shell script executed while starting X Window System session. This is run for every user that logs into X Window
System. It is a good choice for PATH entries that are valid for
every user like /usr/local/something/bin. The file is included by
other script so use POSIX shell syntax not the syntax of your user
shell.
/etc/profile and /etc/profile.d/* Shell script. This is a good choice for shell-only systems. Those files are read only by shells.
/etc/<shell>.<shell>rc. Shell script. This is a poor choice because it is single shell specific.
Also, /etc/environment is not a script file, but rather consists of assignment expressions, one per line. Since this file stores the system-wide locale and path settings, it is most oft quoted choice.
Using /etc/profile is not preferred. It exists only to point to /etc/bash.bashrc and to collect entries from /etc/profile.d
User session
~/.pam_environment. List of unique assignments. Loaded by PAM at the start of every user session irrelevant if it is an X
Window System session or shell. You cannot reference other variable
including HOME or PATH so it has limited use.
~/.xprofile Shell script. This is executed when the user logs into X Window System system. The variables defined here are visible to
every X application. Perfect choice for extending PATH with values
such as ~/bin or ~/go/bin or defining user specific GOPATH or
NPM_HOME. The file is included by other script so use POSIX shell
syntax not the syntax of your user shell. Your graphical text editor
or IDE started by shortcut will see those values.
~/.profile Shell script. It will be visible only for programs started from terminal or terminal emulator. It is a good choice for
shell-only systems.
~/.<shell>rc. Shell script. This is a poor choice because it is single shell specific.
For temporary change:
~$ export PATH=$PATH:~/root/scripts
For permanent change, you can add this line to the /etc/environment file like this:
PATH=$PATH:~/root/scripts
Related
EDIT
The answer to my question is actually obvious, I simply forgot about the meaning of the EXPORT keyword. I still drop the explanation here, just in case.
So in a few words, when opening a terminal with Ctrl-Alt T a new shell is created, which is a child of the shell created at loggin. As explained here, the loggin shell is initialized by reading /etc/profile, and as explained here and more specifically here elements of the environment are transmitted to child processes, notably variables prefixed with the EXPORT keyword.
I am trying to understand what is the mechanism under which the PATH is set under linux when opening a new (virtual) terminal.
I know one can change the PATH in several files (e.g. system : /etc/{profile, bash.bashrc, ... } or user: ~/{.profile, .bash_login, .bashrc... }, some of which are read at login, the others when opening new (virtual) terminals.
According to my tests, it seems the "profile" files are read at startup (when the user logs in), which registers some startup values for variables such as PATH. Then, each time a terminal is opened these startup values are provided to other script (e.g. bashrc) for further configuration, resulting in something like : PATH_IN_TERMINAL=$BASHRC_ADDONS:$PATH_FROM_PROFILE
Notably, ~/.profile won't normally be read after login. Changing this file won't have any effect in the current session and the PATH_FROM_PROFILE part of the PATH will remain the same until one logs in again (after logout or through ssh connection for instance).
Am I correct ? And if so, where can I find a doc on the subject ?
Thanks
This is the best explanation I have found on the subject: Startup Files
The simple explanation, in most common situations is:
Upon initial login to host, read /etc/profile followed by the first of
~/.bash_profile, ~/.bash_login or ~/.profile. ~/.profile is
supported by multiple shells, so is preferred.
When Bash starts, but not immediately after login, read ~/.bashrc.
So, profile files are intended to run upon login and should be used to print initial messages (e.g. Security Warning, Message of the Day), check mail, and configure settings/variables that rarely change. Either system-wide (quotas, MOTD, etc.), or user-specific (timezone, locale, terminal, etc.).
.bashrc files are intended for individual users to customize their interactive experience. e.g. defining aliases, setting prompts, adding to PATH, etc.
I almost always add source ~/.bashrc to the end of my .profile file so that my shell is always customized to my requirements, even immediately after login.
NOTE: The above only applies to interactive shells (e.g. running on a terminal). None of these files are read if bash is run non-interactively (e.g. via cron). In those cases, you should create a different file containing required variables and specify that via the BASH_ENV environment file.
In a graphical DE, like KDE, what command can be used to add a new environment variable that can be used by any other process?
Note:
1) I'm aware of export A=B, but it only works for subsequent processes started in the same shell that executed the export, processes started else where, like a graphical application such as Chrome, won't be aware of the export.
2) I'm also aware that you can put it into ~/.bash_profile or alike, but that would need a restart/relogin for the setting to take effect.
Is there something like export but have effect for all applications and doesn't require a significant restart?
Your assumption that you need to restart after placing a variable definition (whether through an export statement or otherwise) in ~/.bash_profile, is flawed. You only need to source the file again after making modifications:
source ~/.bash_profile
or the more portable version:
. ~/.bash_profile
Either statement will (re)load any definitions in that file into your current shell. Sourcing is not the same as executing the script: it will modify the environment in the calling shell itself, not a subshell running the script.
A file like ~/.bash_profile may have many other definitions and settings in it that will mess with the shell. It is better to create a small (temporary) snippet with just the variables you want, and source that instead, as #JeremiahMegel suggests.
If you want to change the environment for a single process you run from the command line, you can set the variables on the same command line:
VAR=value /usr/bin/gedit
This will run gedit with the environment variable VAR set to value, but only for that one child process.
Unfortunately, your desktop applications are a bit more static than that. Most of the graphical applications you see in the menus are probably going to be represented by .desktop files in a folder like /usr/share/applications. These files are run in an environment that has almost none of the variables you are expecting. They rely on absolute paths, and most of the configuration is done by pointing the .desktop file to a script that performs its own setup. You can modify some of these files on an individual basis if you absolutely have to, but I would not recommend doing that. If you do insist on messing around with the graphical apps on your desktop, I would recommend making a copy of the desktop files you plan to modify in to ~/.local/share/applications, or whatever the equivalent is on your system. Those files will override anything found in /usr/share/applications and will only affect you.
When creating set variables, what is the advantage of adding them to environment? Both are lost at session termination. I know obviously I can add useful stuff to .bashrc that I would want to access via my user.
Just not sure what the advantages would be? how common practice is it? do I need to worry about it? I am talking real life administration uses.
It seems to me like set is a local variable within a class. ENV is obviously global. Maybe the only use is when traversing different shells? How practical is it?
Environment variables are inherited by any process invoked by your shell. That includes both sub-shells and any other commands you invoke.
(Non-environment) shell variables are not.
For example, $TERM needs to be exported, because commands you invoke from your shell (a text editor, a pager, anything that uses a full-screen text display) needs to know what kind of terminal you're using, so it can look up its capabilities in termcap or terminfo. $LANG and similar variables need to be exported so that commands know about the current locale. $PATH needs to be exported so that any commands you invoke can then invoke other commands.
$PS1, the shell prompt, does not need to be exported, because it's relevant only to the current shell (and is typically initialized for new shells).
Can I force BASH to see certain folder (let's call it main_folder) as the root of my file-system? I need BASH to behave this way at least during auto-completion of parameter names and command names, while inside the folder.
Let's say that I have directory tree that looks like this:
/z/y/main_folder/a.txt
/z/y/main_folder/bin/b.txt
/z/y/main_folder/bin/c.txt
/z/y/main_folder/bin/d.sh
Now that I call this custom version of bash, I could simply type:
/> /bi(TAB)/(TAB) /a(TAB)
What would expand to:
/> /bin/d.sh /a.txt
Where d.sh is command to be run and a.txt is it's first parameter. If I was CDed into /bin/ I could do:
/bin/> ./(TAB) (TAB)(TAB)
What would expand the command d.sh, and would give three options for the first parameter (namely: b.txt, c.txt, d.sh).
Few brief additional points:
I do not care if the original root of the file-system is inaccessible or is accessible via hard/soft link.
I do not care if I am able to run any commands that are out of scope for main_folder (I will change the $PATH variable anyway) or any shell builtins.
I do not care what the $PS#, $PWD, etc. variables actually hold.
I do not want to make my own version of BASH (changing source-code). My application should (probably) be started via some script (sh) or program (C/C++/C#) that setups the environment and either continues in interactive mode or runs interactive shell on one of it's last lines.
I want to run this as an unprivileged user. I do not want to allow the user to chroot.
I am not concerned with security, and I am not intending to jail anyone. I simply need BASH to auto-complete.
I would not mind to 'trap' BASH during directory lookups.
I have a feeling that set, compgen, complete and compopt builtins are what I need to utilize, but I do not know how. It does not seem that the examples I have found about these commands show all the features, and man pages are quite chaotic.
Thanks, Kupto :)
I'm trying to setup a project, storm from git:
https://github.com/nathanmarz/storm/wiki/Setting-up-development-environment
Download a Storm release , unpack it, and put the unpacked bin/ directory on your PATH
My question is: What does PATH mean? What exactly do they want me to do?
Sometimes I see some /bin/path, $PATH, or echo PATH.
Can someone explain the concept of PATH, so I can setup everything easily in the future without just blindly following the instructions?
PATH is a special environment variable in UNIX (and UNIX-like, e.g. GNU/Linux) systems, which is frequently used and manipulated by the shell (though other things can use it, as well).
There's a somewhat terse explanation on wikipedia, but basically it's used to define where to search for executable files (whether binaries, shell scripts, whatever).
You can find out what your current PATH is set to with a simple shell command:
: $; echo $PATH
(Note: the : $; is meant to represent your shell prompt; it may be something very different for you; just know that whatever your prompt is, that's what I'm representing with that string.)
Depending on your system and prior configuration, the value will vary, but a very simple example of the output might be something like:
/usr/bin:/bin:/usr/local/bin
This is a colon(:)-separated list of directories in which to search for executable files (things like ls, et cetera.) In short, when you try to execute a command from your shell (or from within some other program in certain ways), it will search through each of the directories in this list, in order, looking for an executable file of the name you're provided, and run the first one it finds. So that's the concept, per your question.
From there, what this documentation is telling you to do is to add the directory where you've unpacked the software, and in particular its bin subdirectory, into your $PATH variable. How to do this depends a bit on which shell you're using, but for most (Bourne-compatible) shells, you should be able to do something like this, if you're in the directory where that bin directory is:
: $; PATH="$PATH:$PWD/bin"; export PATH
In just about all but an actual Bourne shell, this can be shortened to:
: $; export PATH="$PATH:$PWD/bin"
(I won't bother explaining for CSH-compatible shells (because: I agree with other advice that you don't use them), but something similar can be done in them, as well, if that happens to be your environment of choice for some reason.)
Presumably, though, you'll want to save this to a shell-specific configuration file (could be ~/.profile, ~/.bashrc, ~/.zshrc... depending on your shell), and without reference to $PWD, but rather to whatever it expanded to. One way you might accomplish this would be to do something like this:
: $; echo "export PATH=\"\$PATH:$PWD/bin\""
and then copy/paste the resulting line into the appropriate configuration file.
Of course you could also generate the appropriate command in other ways, especially if your $PWD isn't currently where that bin directory is.
See also:
An article about $PATH (and more)
a related question on superuser.com