Trying to understand how the PATH is set on linux (bash on Ubuntu 16.04) - linux

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.

Related

How to ADD an environment variable that can be used by other process in Linux?

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.

Where is PATH variable set in Ubuntu? [duplicate]

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

Unable to add files and directories to PATH

I have a program, let's call it exampleProg, in my /opt directory, and I want to run it from any directory, rather than just:
/opt/radFolder/exampleProg
This should be a simple task, I've done it several times before on different computers. I've searched around, and found instructions ranging from:
edit .bash
edit .bashrc
edit .profile (Another stackoverflow answer said that, while this worked at one time, it no longer functions.)
edit /etc/environment/
with PATH="$HOME/bin:$PATH:/opt/radFolder/:" or just adding the /opt/radFolder bit.
Yet none of them seem to work. The problem that I'm running into is that there doesn't seem to be a yet there doesn't seem to be a universally agreed-upon solution. I've tried so many that I think one of my changes has prevented the appropriate one from taking effect. Would someone help me put this to rest once and for all? Many thanks in advance.
I'm running ubuntu 14.04 LTS x64.
First, understand that writing things to those files does not mean everything is instantaneously, and globally, changed. In fact, nothing is changed until the file is sourced (via . or source), and even then, the environment changes apply only to the current shell (and subsequent created children, if export is used).
INVOCATION, near the top of man bash, spells out which files are automatically sourced when. To summarize:
~/.bashrc is read for new non-login, interactive shells, e.g., when you open a GUI terminal. On many systems, this file by default in turn sources /etc/bashrc.
/etc/profile, ~/.bash_profile, and ~/.profile are read by interactive login shells.
Adding to ~/.bashrc should be effective, but it will only work for subsequently invoked, interactive, non-login shells (and their children, if $PATH is exported). However, since it's prone to being sourced repeatedly, using it to add to an existing variable (as with $PATH) can produce repeated concatenations (see here).
An issue with the second category, .profile, is that if you use a GUI login, the display manager may not source it, but it logs you in, meaning, you never invoke a login shell and hence none of those is ever sourced. If this is the case, sourcing them from ~/.xsession should work (this has a system wide correlate in /etc/X11).

Check from within bash script that autocompletion is initialized

I'm looking for a method to check from within my shell script that script specific completion have been initialized by user using complete -F ...
I want this check to print out an advice on how to initialize the completion like:
Warning: Auto completion is not initialized. Please run : source ....; complete -F ...
The problem is that the script,being run in a sub-shell has no information about "complete" environment of the parent shell where user is working.
So complete -p| grep my-script-name never return any result.
User is expected to run "source" and "complete" commands or add them into his .bashrc manually, because we're working on a server where we have no access to the bash completion system directory.
Alternatively if you know a method of initializing(and not only checking) the auto-complete from within the script, I would happily accept it.
The only way your script can have access to such information for the parent shell is if it is included instead of executed as a sub-shell. Rather than instructing your users they can include some configuration, you can design your script so it works whether it is run or included.
Then you can simply inform your users that if they want completion enabled they need to include your script rather than run it as an executable script (with instuctions to use source or . as you wish).
However, in this case, I would be inclined to either add this information in documentation or add it into a banner which is always displayed (but can be disabled with an option switch like -q), rather than support two modes of running the script (since the gain is so small).
Either you want every user to use bash completion (which I don't think is good, for example I prefer to have it turned off), or let users decide themselves, but having them this message printed out on each TABTAB is a threat, don't you think?
I'd put into /etc/bash.bashrc what you think every user should run.

How do I get GNU screen to read .bash_profile/.bash_rc changes?

After I make changes in .bash_rc or .bash_profile, when I start GNU screen, it doesn't recognize those changes.
I can
source ~/.bash_profile
and it works for the current screen window I have open, but I have to do that for every screen window I have open.
How do I get screen to read my latest changes in my bash configuration?
If you want screen to always treat your shell as a login shell, and source the same files that would be read if just started a new shell normally, add the following to ~/.screenrc (or maybe ~/.byobu/.screenrc, as pointed out in the comment):
shell -$SHELL
This way, you don't need to manually tell it to source your files each time you start a new screen. Though you would have to if you just made changes and wanted those changes to be reflected in your current screen.
The documentation for this (and lots of other screen details) can be found here. Basically, shell is a command to screen telling it to run the following when it needs to create a new shell. $SHELL is the usual variable holding the path to your preferred shell. And the dash - in front of $SHELL indicates that it should be run as a login shell (which will typically mean it sources your ~/.bash_profile, etc.).
It's worth pointing out, however, that screen defaults to just inheriting most environment variables from the shell where you start screen; and a login sub-shell may alter some environment variables in unexpected ways. I ran into a situation where elements of my $PATH were basically permuted. I solved the problem thanks to this particularly excellent answer on superuser.
You may notice the source command available. It's important to note that this sources a file of screen commands, rather than shell commands. Other relevant (screen) commands include eval and exec.
You have to do it in each screen that you have open since they are all different shells. If you need the change every time a new shell is opened, I suggest you put the changes in ~/.bashrc instead.
Apparently, you can send a command to all windows at once using this syntax:
C-a :
at "#" stuff "source ~/.bash_profile^M"

Resources