Suppose I have this in my .profile
export VALUE=x:$VALUE
Then when I start a terminal and do
$ printenv VALUE
x:
the result is what is expected, i.e., VALUE is equal do x:.
Also if I keep launching bash like this
$ printenv VALUE
x:
$ bash
bash-3.2$ printenv VALUE
x:
bash-3.2$
the result is what is expected too.
However, if I start a terminal and launch tmux instead, I get
$ printenv VALUE
x:
$ tmux
$ printenv VALUE
x:x:
and the final VALUE is not equal do x:.
How can I launch tmux so that this does not happen, and it behaves like a fresh bash session?
I am on macOS 10.12.6 (Sierra)
Thanks
There are several reasons why your ~/.profile happens to be sourced more than once.
One would be that tmux is started in a way so that it behaves like a login shell. As such, it will source the ~/.profile naturally (see man bash at INVOCATION). You can start tmux as a login shell by providing the option -l. You didn't mention giving this explicitly, so I guess you didn't, but maybe it was implicitly passed to tmux by some alias or similar. You might want to double check on this (enter type tmux for instance).
The more probable reason is that tmux just starts a shell which then assumes that it is a login shell and thus sources ~/.profile. This in a way is also correct, because starting a terminal muxer can be seen as the process of logging in. More on this can be found here: https://superuser.com/a/970847/153009
The third possibility (which was the reason in my case when I tried to reproduce your case) is that your ~/.bashrc sources your ~/.profile intentionally and explicitly. Although this is against the original design, one finds this very often. Obviously it often solves ugly issues with missing executions of invocation scripts.
You can check for this by giving out ${BASH_SOURCE[*]} in the beginning of the ~/.profile (redirect it to a file to be sure you can see it later).
Because of problems with this, I have the following script snippet in each of my invocation scripts (.bashrc, .profile, etc.):
(
echo "$(date): .profile: $0: $$"; pstree -lp $PPID 2>/dev/null
echo "BASH_SOURCE: ${BASH_SOURCE[*]}"
echo "FUNCNAME: ${FUNCNAME[*]}"
echo "BASH_LINENO: ${BASH_LINENO[*]}"
) >> ~/var/log/config-scripts.log
(Adjust the name .profile in the first line according to the script name of course.)
It seems there is no way to avoid tmux from starting its own shell without inheriting the environment variables of the shell where tmux is called. This means that startup shell scripts must take care if they are running inside tmux. For example, in bash, this can be done
if [ -n "$TMUX" ];
then
echo Inside tmux
else
echo Outside tmux
fi
Related
When starting a new shell, the PATH environment variable is not configured
properly. The directories anaconda3/bin or miniconda3/bin are at second
position only, not at first position in the PATH variable. This can be
resolved by conda deactivate and activating it again.
This question was asked several times already (e.g. here and here)
but the existing questions are either very old or concentrate on the use of
source activate env-name. All in all, I found no answer that resolves my
problem.
When I start a new shell, the base environment is activated. The relevant
snippet from my .bashrc reads like this:
condaexe="/home/$USER/.miniconda3/bin/conda"
condash="/home/$USER/.miniconda3/etc/profile.d/conda.sh"
__conda_setup="$($condaexe 'shell.bash' 'hook' 2> /dev/null)"
# shellcheck disable=SC2181
if [[ $? -eq 0 ]]
then
eval "$__conda_setup"
elif [[ -f "$condash" ]]
then
source "$condash"
fi
unset __conda_setup condaexe condash
Then, the PATH variables are defined as follows:
(base)$ echo $PATH
/home/user/.local/bin:/home/user/.miniconda3/bin:/home/user/.miniconda3/condabin:/home/user/workspace/my-project/:/home/user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
(base)$ conda deactivate && echo $PATH
/home/user/.local/bin:/home/user/.miniconda3/condabin:/home/user/workspace/my-project/:/home/user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ conda activate base && echo $PATH
/home/user/.miniconda3/bin:/home/user/.local/bin:/home/user/.miniconda3/condabin:/home/user/workspace/my-project/:/home/user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
(base)$
Note that /home/user/.local/bin is contained twice; once before and once
after the Miniconda3 directories.
I tried to debug the problem by appending the following snippet to .bashrc:
echo $CONDA_PROMPT_MODIFIER
echo $PATH
This yields
(base)
/home/user/.miniconda3/bin:/home/user/.miniconda3/condabin:/home/user/workspace/my-project:/home/user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
which would be perfectly fine but, somehow, is modified after .bashrc.
Note that here /home/user/.local/bin is contained only once.
What goes on here? How can I setup Bash/Conda to get a properly defined PATH
environment variable?
There are three components I missed in the original question which are key to the solution.
First, I run all my shells inside TMux. Second, TMux sources the .profile. Third, in .profile some local directories like the aformentioned ~/.local/bin are blindly prepended to the PATH.
Taken this altogether all the weird behaviour above makes sense. Especially that PATH is correct at the end of ~/.bashrc but not in the shell is obvious now; it got modified in between by ~/.profile.
There are three solutions for this:
deactivating and activating conda manually (temporary workaround)
being more picky about which shells are started inside TMux (very unhandy)
commenting out the manipulations of PATH in ~/.profile
It seems as if one cannot configure TMux to source only ~/.bashrc (reference 1, reference 2), albeit some workarounds exist here too.
This is related to the Bash init files. By default, ~/.bashrc is used in an interactive, non-login shell. It won't be sourced in a login shell. Tmux uses a login shell by default. Hence, shells started by tmux skip ~/.bashrc.
default-command shell-command
The default is an empty string, which instructs tmux to create a login shell using the value of the default-shell option.
Init files for Bash,
login mode:
/etc/profile
~/.bash_profile, ~/.bash_login, ~/.profile (only first one that exists)
interactive non-login:
/etc/bash.bashrc (some Linux; not on Mac OS X)
~/.bashrc
non-interactive:
source file in $BASH_ENV
The weird interactive, non-login loading requirement confuses people in other situations as well. The best solution is to change the loading requirement of ~/.bashrc as interactive only, which is exactly what some distros, like Ubuntu, are doing.
# write content below into ~/.profile, or ~/.bash_profile
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
This should be the solution you desire. And I recommend every Bash user setup this in the profile.
References
Unix Shell Initialization
man tmux
Thanks for this post! That give me hint to debug same issue. I think everyone is different situdation but the idea is same: there is a command like export $PATH change the path in your zshrc or .bashrc which will affect the computer to find the path you want.
I am seeing a strange problem with the storing of an env in mac os.
I set custom env in ~/.bash_profile
export MYENV=user
Then ran the . ~/.bash_profile and then I printed the env using
printenv then I can see the MYENV=user in the list.
If I close the terminal and reopen and execute printenv then I could not see MYENV in the list still I can see the export MYENV=user in ~/.bash_profile. It seems strange to me.
I am using Mac os High Sierra 10.13.6.
Could some body please tell me what mistake I am doing?
Note that ~/.bash_profile is only run for login shells. From the man page:
When bash is invoked as an interactive login shell, or as a non-interactive shell
with the --login option, it first reads and executes commands from the file
/etc/profile, if that file exists. After reading that file, it looks for
~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and exe-
cutes commands from the first one that exists and is readable. The --noprofile
option may be used when the shell is started to inhibit this behavior.
So if you terminal isn't launching the shell with -l, --login or with $0 having a leading hyphen it won't be a login shell and thus won't read ~/.bash_profile. You may need to reconfigure how your terminal launches the shell if you want the shell to read that config script.
On the other hand ~/.bashrc is always read by an interactive shell. So if you put the export in that script it should do what you expect. It certainly does for me. You replied to Amila that it didn't work for you. So I'd suggest a simple experiment. Open two terminal windows. In one edit ~/.bashrc and add these two lines:
echo running .bashrc
export WTF=abc
In the other window just run bash. It should echo that message and echo $WTF should print abc. Now open a new terminal window. If you don't see that message and the env var isn't present then something is inhibiting reading that config script. Possibly the shell is being run with the --norc flag.
~/.bash_profile is executed before the initial command prompt is returned to the user, which means after a new login. Try adding the environment variable to ~/.bashrc instead.
My goal is to have a set of dot files shared between the many shell accounts I have so that I can have a similar environment in each one. Because of that, I don't want machine/environment specific information in my .git files or my .bash files.
On my MacOSX machine, the default emacs version is 22. I have installed a newer version of emacs (24) in /usr/local/bin. In my .bashrc file I set my default editor to emacs: export EDITOR=emacs. Before this, I also set up my path so that /usr/local/bin comes before /usr/bin so that the newer version of emacs gets selected.
When I use git to create commit messages, it always picks the one in /usr/bin instead of the one in /usr/local/bin. Git is ignoring my $PATH settings. I used to hardcode the location of the version of emacs I wanted in my .gitconfigure file, but that won't work when I use that same .gitconfigure file on my Ubuntu server. (If it's unclear, what I'm saying is that modifying my .gitconfigure editor option to point to a hardcoded won't work for me).
Why doesn't git respect my $PATH settings?
How do I configure git to use the correct emacs?
Edit: Adding more context
There is a suggestion to put environment variables in .profile/.bash_profile. Here's some relevant code from my .bashrc and my .bash_profile
.bashrc
Note: I wrote a bash function called vercomp which compares version numbers.
OS=''
case $OSTYPE in
darwin*) OS='Mac' ;;
linux*) OS='Linux' ;;
*) OS='UNKNOWN' ;;
esac
export EDITOR=emacs
if [[ $OS = 'Mac' ]]; then
### EMACS VERSION CHECK
# make sure that we're working with emacs >= 24
wanted_ver=24
curr_ver=`emacs --version | grep -oE '[[:digit:]]+\.[.[:digit:]]*'`
vercomp $curr_ver $wanted_ver
# If vercomp returns 2, then our current emacs version isn't good enough.
if [[ $? == 2 ]]; then
if [[ -e '/usr/local/bin/emacs' ]]; then
emacs_path='/usr/local/bin/emacs -nw'
elif [[ -e '/Applications/Emacs.app/Contents/MacOS/Emacs' ]]; then
emacs_path='/Applications/Emacs.app/Contents/MacOS/Emacs -nw'
else
echo -n "EMACS VERSION OUT OF DATE: $curr_emacs_version. "
echo 'Install a newer version.'
emacs_path=''
fi
export EDITOR="$emacs_path"
alias emacs="$emacs_path"
fi
fi
.bash_profile
source ~/.bashrc
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell
session *as a function*
LESS=-FRX;export LESS
I expect to have an answer that explains WHY MacOSX doesn't pick up my
bashrc/profile environment changes and a solution to HOW I can get
MacOSX to pick up those changes.
This is not specific to OS X - here is an example:
$ uname -a
Linux hostname 3.13.7-gentoo #1 SMP PREEMPT Mon Mar 24 18:40:46 CET 2014 i686 Intel(R) Atom(TM) CPU 330 # 1.60GHz GenuineIntel GNU/Linux
$ cat .bashrc
export EDITOR="emacs"
$ echo $EDITOR
/usr/bin/vim
$ mv .bashrc .bash_profile
$ logout
Connection to hostname closed.
$ ssh hostname
$ echo $EDITOR
emacs
For what I know and used to "live" is that environment variables are expected to reside inside /etc/profile (system wide) and can be extended and overwritten on a user level basis inside ~/.profile respectively ~/.bash_profile.
From man bash:
When bash is invoked as an interactive login shell, or as a
non-interac- tive shell with the --login option, it first reads
and executes commands from the file /etc/profile, if that file
exists. After reading that file, it looks for ~/.bash_profile,
~/.bash_login, and ~/.profile, in that order, and reads and
executes commands from the first one that exists and is readable.
On the other hand. .bashrc is the place to go where one places custom functions, aliases, prompt configuration, etc.
So a simple solution to your specific question - aside from using another git version in your special situation - would be to simply move your environmant variables from your .bashrc into a .bash_profile.
The Linux From Scratch project provides some pretty good examples about how to organize the bash shell startup files. Specific problems on OS X are tackled inside "Setting environment variables in OS X?".
Do not set variables in .bashrc. Bash only looks at this file in interactive sessions, so programs outside of an interactive session will never see any variables from .bashrc.
For bash, environment variables belong into ~/.profile!.
To fix your problem immediately, you may set $EDITOR to an absolute path:
if [[ -e /usr/local/bin/emacs ]]; then
export EMACS=/usr/local/bin/emacs
else
export EMACS=emacs
However, the issue points to a deeper problem in your environment setup, but your question currently lacks some information (see my comment).
Generally, $PATH and environment variables are a mess on OS X, because there's no single place to change them (for instance, profile variables do not propagate to the desktop and GUI applications), and because OS X itself meddles with $PATH by means of path_helper. You need to be extra careful about where you set variables, and you need use workarounds like exec-path-from-shell to have your environment variables available in GUI applications.
Any program is free to set PATH inside of itself to whatever it wants -- this tactic is often used in setuid programs to prevent execution of the wrong (or downright bad) executables.
You'll need to find out whether Emacs Terminal.app creates a Bash that runs ~/.bashrc, ~/.bash_profile, both, or something else entirely. (Sorry, I'm a vim user.)
Try this:
export VISUAL=emacs
I just tried export VISUAL=gedit from bash on my Ubuntu and now git uses gedit
when called from that terminal.
This has been frustrating me for two days and it seems like it should be a very simple thing. I was just created an account on a Solaris machine. Sun OS 5.10 I believe.
The default is Bourne shell which I don't want. I did a cat /etc/shells which results in:
/bin/sh
/sbin/sh
/bin/ksh
/usr/bin/ksh
Looks like Korn shell is all I can use.
I created a .profile file and wrote:
export SHELL=/usr/bin/ksh
Then I did a env and it looks like /bin/sh is still listed as my shell. I logged off, logged back on and now I get:
-sh: SHELL=/usr/bin/ksh: is not an identifier
I've tried adding #!/usr/bin/ksh at the beginning of the .profile. That didn't work. I've tried adding a semicolon at the end of the export. That didn't work. I've tried: SHELL=/bin/ksh and that didn't work either.
My end goal is to get this environment to a point where I can operate productively. I'm used to BASH where I have tab-completions, up-arrow for history, etc and this Bourne shell doesn't have any of that and it frustrates me to no end.
I know this must be simple but all my Googling comes to no avail. Can someone help me?
/etc/shells is not a standard Solaris file, you probably shouldn't rely on its contents.
On the other hand, bash is part of the default Solaris 10 installation. It should already be present as /bin/bash (/usr/bin/bash actually but /bin is a symlink to /usr/bin anyway).
If bash is not there, you might want to ask to the administrator to install the SUNWbash package from the Solaris_10/Product directory in the installation media.
Then, to update your shell, the regular way is to have the shell defined for your account updated. If it is local, that's the last field in your /etc/passwd entry.
Alternatively, you might use that hack at the end of your .profile:
[ ! "$BASH_VERSION" -a -x /bin/bash ] && SHELL=/bin/bash exec /bin/bash
In descending order of preference
ask the sysadmin to install bash and update /etc/shells and update your login shell
see if the chsh program is installed that will allow you to change your own login shell
ask the sysadmin to change your login shell to /usr/bin/ksh
modify your ~/.profile:
if type [[ >/dev/null; then
: # this is ksh
else
# not ksh
export SHELL; SHELL=/usr/bin/ksh
exec $SHELL
fi
How can I tell what type my shell is? ie, whether it's traditional sh, bash, ksh, csh, zsh etc.
Note that checking $SHELL or $0 won't work because $SHELL isn't set by all shells, so if you start in one shell and then start a different one you may still have the old $SHELL.
$0 only tells you where the shell binary is, but doesn't tell you whether /bin/sh is a real Bourne shell or bash.
I presume that the answer will be "try some features and see what breaks", so if anyone can point me at a script that does that, that'd be great.
This is what I use in my .profile:
# .profile is sourced at login by sh and ksh. The zsh sources .zshrc and
# bash sources .bashrc. To get the same behaviour from zsh and bash as well
# I suggest "cd; ln -s .profile .zshrc; ln -s .profile .bashrc".
# Determine what (Bourne compatible) shell we are running under. Put the result
# in $PROFILE_SHELL (not $SHELL) so further code can depend on the shell type.
if test -n "$ZSH_VERSION"; then
PROFILE_SHELL=zsh
elif test -n "$BASH_VERSION"; then
PROFILE_SHELL=bash
elif test -n "$KSH_VERSION"; then
PROFILE_SHELL=ksh
elif test -n "$FCEDIT"; then
PROFILE_SHELL=ksh
elif test -n "$PS3"; then
PROFILE_SHELL=unknown
else
PROFILE_SHELL=sh
fi
It does not make fine distinctions between ksh88, ksh95, pdksh or mksh etc., but in more than ten years it has proven to work for me as designed on all the systems I were at home on (BSD, SunOS, Solaris, Linux, Unicos, HP-UX, AIX, IRIX, MicroStation, Cygwin.)
I don't see the need to check for csh in .profile, as csh sources other files at startup.
Any script you write does not need to check for csh vs Bourne-heritage because you explicitly name the interpreter in the shebang line.
Try to locate the shell path using the current shell PID:
ps -p $$
It should work at least with sh, bash and ksh.
If the reason you're asking is to try to write portable shell code, then spotting the shell type, and switching based on it, is an unreliable strategy. There's just too much variation possible.
Depending on what you're doing here, you might want to look at the relevant part of the autoconf documentation. That includes an interesting (and in some respects quite dismal) zoology of different shell aberrations.
For the goal of portable code, this section should be very helpful. If you do need to spot shell variants, then there might be some code buried in autoconf (or at least in one of the ./configure scripts it generates) which will help with the sniffing.
You can use something like this:
shell=`cat /proc/$$/cmdline`
Oh, I had this problem. :D
There is a quick hack, use ps -p $$ command to list the process with PID of the current running process -- which is your SHELL. This returns a string table structure, if you want, you can AWK, or SED the shell out...
The system shell is the thing you see when you open up a fresh terminal window which is not set to something other than bash (assuming this is your default SHELL).
echo $SHELL
Generally, you can find out all the constants defined by running
set
If the output is a lot of stuff then run
set | less
so you can scroll it from the top of the command line or
set > set.txt
To save the output to a file.
Invoking a different interactive shell to bash in your terminal does not mean that your system shell gets changed to something else i.e. your system shell is set to bash although you invoke a csh shell from a bash shell just that one session.
The above means that typing /bin/csh or /bin/python in bash or whatever does not set the system shell to the shell you invoked, at all.
If you really want to see the SHELL constant change then you need to set it to something else. If successful you should see the new shell whenever you open a fresh terminal...
It's old thread but...
In GNU environment You can sh --help and get something like
BusyBox v1.23.2 (2015-04-24 15:46:01 GMT) multi-call binary.
Usage: sh [-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]
Unix shell interpreter
So, the first line is shell type =)