how to set up env variable in bash? - bash

I want my bash script to set PYTHONPATH to the pwd.
so
EXPORT PYTHONPATH=`pwd` ?
How could I accomplish that?

According to
the source
if you are using a login shell
echo 'export PYTHONPATH=`pwd`' >> ~/.bash_profile
if you are using a non-login shell
echo 'export PYTHONPATH=`pwd`' >> ~/.bashrc

Related

Dockerfile doesn't source .bashrc even in a single subshell

I'm trying to source .bashrc but no luck
USER user
SHELL ["/bin/bash", "-c"]
RUN echo "export TEST_VAR=test" >> /home/user/.bashrc && tail /home/user/.bashrc && source /home/user/.bashrc && echo "1 \"${TEST_VAR} 2\" var" && exit 1
I expect that this RUN command print 1 "test" 2 but what i get is that
Step 13/40 : RUN echo "export TEST_VAR=test" >> /home/user/.bashrc && tail /home/user/.bashrc && source /home/user/.bashrc && echo "1 \"${TEST_VAR}\" 2" && exit 1
---> Running in b870d36e9dd0
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
export TEST_VAR=test
1 "" 2
What's wrong with handling shells in docker? I just wanted to source ~/.bashrc once and use all exposed variables in subsequent command below source call but it doesn't even work in a single subshell joined with &&
Usually ~/.bashrc contains something similar to:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
That is very normal - .bashrc is meant to be used in interactive sessions only. Because RUN is non-interactive, it just exits.
Aaaanyway, I would recommend, if you want to only add environment variables, output them to /etc/profile.d and . /etc/profile.
Most paths in Docker don't read shell dotfiles at all. You need to use other approaches to provide configuration to your application; for example, Dockerfile ENV to set environment variables or an entrypoint wrapper script if you need things to be set up dynamically before starting the container.
Let's look specifically at a reduced form of your example:
SHELL ["/bin/bash", "-c"]
RUN echo "export TEST_VAR=test" >> $HOME/.bashrc
RUN echo "$TEST_VAR"
Bash Startup Files in the GNU Bash manual lists out which dotfiles are read in which case. For the last line Docker combines the SHELL and RUN lines to run the equivalent of
/bin/bash -c 'echo "$TEST_VAR"'
but the bash instance is neither an interactive nor a login shell, so the only dotfile that's automatically read is one named in a $BASH_ENV environment variable. (POSIX sh doesn't specify anything about any shell dotfiles at all.)
This further applies to the image's default CMD, which also will get run with sh -c (or the alternate SHELL) and it won't read dotfiles. If the CMD (or ENTRYPOINT or RUN) uses JSON-array syntax, it won't invoke a shell at all, and again won't read dotfiles.
The only case where shell dotfiles will be read is if the main container command is an interactive shell, and this won't typically be the common case.
docker run --rm -it yourimage /bin/bash # reads .bashrc
docker run --rm -it yourimage /bin/bash --login # also reads .profile, .bash_login
This means you should almost never try to edit the .bashrc, /etc/profile, or any similar files. If you need to set environment variables as in the example, use Dockerfile ENV instead.
ENV TEST_VAR=test
RUN echo "$TEST_VAR"

Making bash script continue after exec $SHELL

I'm making a bash script that would install rbenv and ruby.
cd
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
exec $SHELL
rbenv install $rubyVersion
rbenv global $rubyVersion
But when the exec $SHELL is called the bash process is replaced by new bash process and the script stops (of course).
How can I make the script to continue?
It appears that you're trying to achieve multiple objectives by modifying the .bashrc file then calling exec $SHELL. Neither of those actions will modify the shell-in-which-this-script-is-running. To modify the current shell, you want to "source" the .bashrc file. Use the "dot notation" instead of calling exec $SHELL:
. ~/.bashrc
Good luck with this one!
replace exec $SHELL lines with "$SHELL" lines or completely remove those lines

bash: parse_git_branch: command not found

This should be very simple.
I recently noticed that when I type 'bash' into Terminal on Mac it shows this:
Jays-MacBook-Pro: ~ $ bash
bash: parse_git_branch: command not found
When before it didn't. Can someone explain why and how to resolve.
It is likely that you configured BASH to run parse_git_branch and print the result as part of PS1 (or alike). You can check this by: "echo $PS1" and "echo $PROMPT_COMMAND".
However, parse_git_branch is not a builtin function of bash. Below is how I configured my PS1. You may want to copy my git_branch_4_ps1 as your parse_git_branch
PS1='\n' # begin with a newline
PS1=$PS1'\[\e[38;5;101m\]\! \t ' # time and command history number
PS1=$PS1'\[\e[38;5;106m\]\u#\h ' # user#host
PS1=$PS1'\[\e[7;35m\]${MY_WARN}\[\e[0m\] ' # warning message if there is any
PS1=$PS1'\[\e[38;5;10m\]${MY_EXTRA} ' # extra info if there is any
PS1=$PS1'\[\e[0;36m\]$(git_branch_4_ps1) ' # git_branch_4_ps1 defined below
PS1=$PS1'\[\e[38;5;33m\]\w' # working directory
PS1=$PS1'\n\[\e[32m\]\$ ' # "$"/"#" sign on a new line
PS1=$PS1'\[\e[0m\]' # restore to default color
function git_branch_4_ps1 { # get git branch of pwd
local branch="$(git branch 2>/dev/null | grep "\*" | colrm 1 2)"
if [ -n "$branch" ]; then
echo "(git: $branch)"
fi
}
If your parse_git_branch is defined in ~/.bash_profile, it will not be loaded when you open a non-login shell (e.g. by running bash).
The differences between login and non-login shells are described here: Difference between Login Shell and Non-Login Shell? For our purposes, the main difference is that login shells (e.g. that when you first open Terminal) automatically source ~/.bash_profile upon startup, whereas non-login shells (e.g. that when you run bash from within Terminal) do not.
To fix this error, simply source your ~/.bash_profile after running bash:
user#host:~ $ bash
bash: parse_git_branch: command not found
user#host:~ $ source .bash_profile
Alternatively, place the function in ~/.bashrc instead, which will be automatically sourced by non-login shells (as covered in the earlier link).
Instead of having
parse_git_branch
call in PS1 definition alone you may use
parse_git_branch 2>/dev/null
to send stderr to /dev/null. This will silence the error you don't want to see.
have you export your $PS1 ?
You can check by run command:
printenv
else you should export it by run:
export -n PS1
after you will can run sudo or sudo su without problem
The key to this is to NOT export PS1. If it's exported, then any non-login shell also takes PS1. Since .bash_profile is automatically source'd by the login shell, the PS1 variable only affects the login shell.

export /etc/environment variables to current environment; from a shell script?

How do I bring environment variables from /etc/environment to the terminal and what it calls?
file0.bash
#!/usr/bin/env bash
bash ./file1.bash
echo $FOO_BAR
for line in $( sudo cat /etc/environment ); do export $line; done
file1.bash
#!/usr/bin/env bash
sudo sed -i '/^FOO_BAR/d' /etc/environment
printf FOO_BAR="$HOME/Foo\n" | sudo tee -a /etc/environment
for line in $( sudo cat /etc/environment ); do export $line; done
Console
$ echo $FOO_BAR
$ bash file0.bash
[sudo] password for myusername:
FOO_BAR=/home/myusername/Foo
$ echo $FOO_BAR
$ # What I want to avoid is having to revert to this:
$ for line in $( sudo cat /etc/environment ); do export $line; done
$ echo $FOO_BAR
/home/myusername/Foo
When you execute a script as:
bash ./file.bash
OR else:
./file1.bash
Running a shell script like this launches a new process, a subshell.
All the variables created in a subshell are not visible outside the block of code in the subshell. They are not accessible to the parent process, to the shell that launched the subshell. These are, in effect, variables local to the child process. Note that exporting variables also won't make them available in the parent shell. That just makes them available to further subshells of the running subshell.
To change this behavior you can force script to execute in current shell itself using any of these 2 way:
source ./file1.bash
OR
. ./file1.bash

Using bash shell inside Matlab

I'm trying to put a large set of bash commands into a matlab script and manage my variables (like file paths, parameters etc) from there. It is also needed because this workflow requires manual intervention at certain steps and I would like to use the step debugger for this.
The problem is, I don't understand how matlab interfaces with bash shell.
I can't do system('source .bash_profile') to define my bash variables. Similarly I can't define them by hand and read them either, e.g. system('export var=somepath') and then system('echo $var') returns nothing.
What is the correct way of defining variables in bash inside matlab's command window? How can I construct a workflow of commands which will use the variables I defined as well as those in my .bash_profile?
If all you need to do is set environment variables, do this in MATLAB:
>> setenv('var','somepath')
>> system('echo $var')
Invoke Bash as a login shell to get your ~/.bash_profile sourced and use the -c option to execute a group of shell commands in one go.
# in Terminal.app
man bash | less -p 'the --login option'
man bash | less -p '-c string'
echo 'export profilevar=myProfileVar' >> ~/.bash_profile
# test in Terminal.app
/bin/bash --login -c '
echo "$0"
echo "$3"
echo "$#"
export var=somepath
echo "$var"
echo "$profilevar"
ps
export | nl
' zero 1 2 3 4 5
# in Matlab
cmd=sprintf('/bin/bash --login -c ''echo "$profilevar"; ps''');
[r,s]=system(cmd);
disp(s);

Resources