/etc/profile does not appear to run - macos

I'm on OS X and according to man bash /etc/profile is the system wide configuration for the bash shell.
For testing purposes I opened this file up :
open_profile(){
sudo chmod 777 /etc/profile
}
and added an echo so that I can see if it is actually running.
It is not:
# System-wide .profile for sh(1)
echo "test_global"
if [ -x /usr/libexec/path_helper ]; then
eval `/usr/libexec/path_helper -s`
fi
if [ "${BASH-no}" != "no" ]; then
[ -r /etc/bashrc ] && . /etc/bashrc
fi
I do not see the echo when I open up a bash shell.

/etc/profile is only invoked for login shells. To force a login shell vice an non-login shell add --login.
bash --login
When Bash is invoked as a login shell, or as a non-login 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.

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"

Bash Echo passing to another script, not working as expected

I created a bash file to write some content into a file, which should be written into another users home directory, with the users account.
It should work the follwing:
sudo ./USER.sh run 49b087ef9cb6753f "echo test > test.txt"
Basically USER.sh contains this:
if [ "$1" = "run" ]; then
cd /home/${2}/;
sudo -u ${2} ${3};
fi
But it does not write any stuff into test.txt, it just direct executes the Bash command, instead of writing it into the file.
Did anyone got an Idea how I can fix it, that it does actually write the Content into a file instead of direct executing it?
Thanks.
You want:
sudo -u "$2" sh -c "$3"
The curlies are useless. They don't prevent splitting and file-globbing.
The double quotes do.
With the double quotes "$3" expands to "echo test > test.txt" (without them, it's "echo" "test" ">" and "test.txt"). This needs to be executed by a shell, hence the sh -c (a POSIX shell is sufficient in this case and if it's dash, it'll start a few ms faster than bash does).
You could also do:
if [ "$1" = "run" ]; then
sudo -u "$2" --set-home sh -c "$(printf '%s\n' 'cd "$HOME"' "$3")"
fi
which would be more robust in the general case where user home directories aren't necessarily /home/$username, but whatever the appropriate field in /etc/passwd is.

Running command as login shell without starting a new shell?

I'm trying to see what the output of a command would be if I were in a login shell, without having to go into a login shell. I've tried several variations of
zsh --login -c "alias"
But none of my aliases get shown; are --login and -c incompatible?
To test the difference between zsh --login -c "alias" and a normal login shell, you can/should add the -x option to see what the shell is up to.
When I run zsh -x --login -c "alias", then it processes /etc/zprofile.
When I run zsh -x --login, then it processes /etc/zprofile and /etc/zshrc.
I don't normally use zsh, so I don't have any personalized profile or start up file for it, but it seems plausible that it might look for (but, in my case, not find) ~/.zprofile and ~/.zshrc too.
I created trivial versions of those files:
$ echo "echo in .zprofile" > ~/.zprofile
$ echo "echo in .zshrc" > ~/.zshrc
and sure enough, they're processed. Further, the -c command with --login processed the .zprofile but did not process the .zshrc file.
Thus, using -c "alias" after the --login suppresses the processing of /etc/zshrc and ~/.zshrc. If you want those executed even so, you need to use something like:
zsh --login -c "[ -f /etc/zshrc ] && . /etc/zshrc; [ -f ~/.zshrc ] && . ~/.zshrc; alias"
Using -x to debug login processing is often informative.
It's nice that modern shells provide a command line option to induce login processing. I still have a program (which I don't use any more) that runs a login shell the old-fashioned way, by adding a - before the shell name in argv[0]. Thus, running -ksh would trigger login processing; the login program would run the login shell with the - at the start.

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.

Running system command under interactive bash shell

I am trying to run a command that has been aliased in my ~/.bashrc from Perl using the system command. It works well running the command only once, but when I run it twice the second invocation is run as a background job and then suspended (the same as pressing <CTRL-Z>) and I have to type fg to complete the command. For example
use strict;
use warnings;
system ('bash -ic "my_cmd"');
system ('bash -ic "my_cmd"');
The second call never completes. The output is [1]+ Stopped a.pl.
Note:
The same result is obtained when replacing my_cmd with any other command, for example ls.
It seems not to depend of the contents of my ~/.bashrc file. I tried to remove everything from it, and the problem still persisted.
I am using Ubuntu 14.04 and Perl version 5.18.2.
Update
For debugging I reduced my ~/.bashrc to
echo "Entering ~/.bashrc .."
alias my_cmd="ls"
alias
and my ~/.bash_profile to
if [ -f ~/.bashrc ]; then
echo "Entering ~/.bash_profile .."
. ~/.bashrc
fi
Now running:
system ('bash -lc "my_cmd"');
system ('bash -lc "my_cmd"');
gives
Entering ~/.bash_profile ..
Entering ~/.bashrc ..
alias my_cmd='ls'
bash: my_cmd: command not found
Entering ~/.bash_profile ..
Entering ~/.bashrc ..
alias my_cmd='ls'
bash: my_cmd: command not found
and running
system ('bash -ic "my_cmd"');
system ('bash -ic "my_cmd"');
gives
Entering ~/.bashrc ..
alias my_cmd='ls'
a.pl p.sh
[1]+ Stopped a.pl
Rather than using the -i switch for an interactive shell, I think you should use the -l (or --login) switch, which causes bash to act as if it had been invoked as a login shell.
Using the -l switch doesn't load ~/.bashrc by default. According to man bash, in a login shell, /etc/profile/ is loaded, followed by the first file found from ~/.bash_profile/, ~/.bash_login or ~/.profile/. On my system, I have the following in ~/.bash_profile, so ~/.bashrc is loaded:
# Source .bashrc
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
Now that your ~/.bashrc is being loaded, you need to enable the expansion of aliases, which is off in a non-interactive shell. To do this, you can add the following line before setting your aliases:
shopt -s expand_aliases
A process randomly stopping - aside from ctrl-z is usually when it needs STDIN, but doesn't have it attached.
Try it with - for example passwd &. It'll background and go straight into 'stopped' state. This may well be what's happening with your bash command. -i means interactive shell, explicitly, and you're trying to do something noninteractive with it.
That's almost certainly not the best approach, you probably want to do something different. bash --login might be closer to what you're after.
Tom Fenech's answer worked for me in Ubuntu 16.04.1 LTS with a small addition. At the top of my ~/.bashrc file, I commented out the following section so that if the shell is not interactive (e.g., a login shell), ~/.bashrc is still read. On some other versions of Linux I don't see this section.
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac

Resources