Can't execute nvm from new bash - bash

When I open a new bash, nvm command is not found. It seems that the ~/.nvm/nvm.sh is not being loaded on bash startup.
I have added the line below to ~/.bashrc
[[ -s /home/$USER/.nvm/nvm.sh ]] && . /home/$USER/.nvm/nvm.sh
Any ideas why it is happening?

If you are running from a new bash instance, and you HAVE the initialization code at your ~/.bashrc, ~/.bash_profile, etc, then you need to check this initialization file for conditionals.
On Ubuntu 14, there is a:
case $- in
*i*) ;;
*) return;;
esac
At line 6, that will halt it's execution if bash is not being ran with the "-i" (interactive) flag. So you would need to run:
bash -i
Also, at the end of the file, there is a
[ -z "$PS1" ] && return
That will halt it's execution if not being ran with $PS1 set (like on a remote ssh session).
If you do not wish to add any env vars or flags, you will need to remove those conditionals from your initialization file.
Hope that's helpful.

Related

Why `~/.bashrc` is not executed when run docker container?

I have a docker file as below. launch.sh is the entry point in this docker image.
FROM ubuntu:16.04
USER root
RUN apt-get update && apt-get install -y \
curl \
vim \
net-tools \
git \
iputils-ping \
wget
RUN apt-get install -y python
RUN apt-get update && apt-get install -y gcc g++ make libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
ENV NVM_DIR /root/.nvm
RUN . $NVM_DIR/nvm.sh && \
nvm install 7.9.0 && npm install -g npm#5.6.0
ADD ./Docker/launch.sh /workspace/
CMD ["/bin/sh", "/workspace/launch.sh"]
The content of launch.sh is:
#!/bin/bash
cd /workspace/demo
npm install
node index.js
when I run the docker container: docker run IMAGE_NAME, I got this error:
npm: not found
node: not found
The node in this image is managed by nvm which has been installed and its script has been set on /root/.bashrc file. But I don't know why it can't find the nodejs commands. But if I run the container by docker run -it IMAGE_NAME bash, then manually run workspace/launch.sh command, everything works fine. It seems the ~/.bashrc is not executed when run the image. How can I let the container source .bashrc?
The content of /root/.bashrc is:
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
# don't put duplicate lines in the history. See bash(1) for more options
# ... or force ignoredups and ignorespace
HISTCONTROL=ignoredups:ignorespace
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes
if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u#\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u#\h:\w\$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user#host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u#\h: \w\a\]$PS1"
;;
*)
;;
esac
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
#if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
# . /etc/bash_completion
#fi
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
Each command runs a separate sub-shell, so the environment variables are not preserved and .bashrc is not sourced (see this answer).
You have to source your script manually in the same process where you run your command so it would be:
CMD source /root/.bashrc && /workspace/launch.sh
provided your launch.sh is an executable.
As per documentation exec form you are using does not invoke a command shell, so it won't work with your .bashrc.
Edit:
BASH wasn't your default shell so
CMD /bin/bash -c "source /root/.bashrc && /workspace/launch.sh"
was needed in order to run your script.
If you want yo set your shell as BASH by default, you can use SHELL instruction as described in documentation, e.g.:
SHELL ["/bin/bash", "-c"]
None of the existing answers accurately answer the title question: Why ~/.bashrc is not executed when run docker container?
There are two things to be aware of:
Use login shell
According to the bash 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 executes 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.
Therefore, in order to have .profile/.bashrc read automatically upon invocation of bash, it is necessary to invoke bash with the --login or -l option.
You can do this in a couple ways:
1. Set the shell to include -l option. For example,
SHELL ["/bin/bash", "-l", "-c"]
2. Invoke -l for specific commands using the exec form of RUN:
CMD ["/bin/bash", "-l", "-c", "/workspace/launch.sh"]
Note top of .bashrc
From the man page above, we know the order in which profile files are searched and loaded. If you look at /root/.profile you may see something like this:
# ~/.profile: executed by Bourne-compatible login shells.
if [ "$BASH" ]; then
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
fi
mesg n 2> /dev/null || true
This is how ~/.bashrc gets source for a bash shell. Therefore, we can expect ~/.bashrc to be sourced when the bash shell is used.
However, look carefully near the top of your .bashrc file:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
This means that effectively the remaining contents of .bashrc are ignored except for interactive shells.
One answer suggests using the -i option of bash to invoke an interactive shell. This does work because the environment variable PS1 is set for interactive shells, and therefore .bashrc continues.
However, perhaps you don't want an interactive shell. In this case, there are a few options:
1. Comment out the return line. You can use something like this in your Dockerfile:
RUN sed -e '/[ -z "$PS1" ] && return/s/^/#/g' -i /root/.bashrc
This modification to .bashrc will prevent its early exit from non-interactive invocations.
2. Move the nvm setup to .profile. Move the last three lines of your .bashrc file to .profile so they're executed unconditionally.
3. Manually source .bashrc. As other answers have already noted, you can certainly manually source .bashrc as needed, as in,
RUN source /root/.bashrc && /workspace/launch.sh
Observe that much of the content of .bashrc makes the most sense for interactive shells and is usually unnecessary otherwise, which may make option 2 above the most appealing.
with CMD and shell form
CMD /bin/bash -i "/workspace/launch.sh"
Edit
should also work with ENTRYPOINT and and using exec form using
ENTRYPOINT ["bash","-i","/workspace/entrypoint.sh"]
I believe the -i flag works in the intended way, the .bashrc file is used as intended, the other solutions did not work for me, the .bashrc file was never used
solution may not be ideal for everyone, with the -i flag the program may prompt for user interaction
ps: I used docker create and docker start -i "container name"
You can add source /path/to/bashrc in launch.sh and change the CMD to the following instead of changing to bash through CMD itself:
CMD ["/workspace/launch.sh"]
Alternatively, You can do the following in your Dockerfile instead of depending on bashrc
ENV NVM_DIR /root/.nvm
ENV NODE_VERSION 7.9.0
ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules #Ensure that this is the actual path
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH
RUN . $NVM_DIR/nvm.sh && \
nvm install $NODE_VERSION && npm install -g npm#5.6.0

Using anyenv in Fish Shell

I tried to using anyenv in Fish Shell but the error occured.
This is my ~./config/fish/config.fish file.
set -x PATH $HOME/.anyenv/bin $PATH
eval (anyenv init -)
What's wrong with this?
Errors which I got:
$# is not supported. In fish, please use 'count $argv'.
- (line 1): begin; source "/Users/kasumi/.anyenv/libexec/../completions/anyenv.bash" anyenv() { typeset command command="$1" if [ "$#" -gt 0 ]; then shift fi command anyenv "$command" "$#" } export NDENV_ROOT="/Users/kasumi/.anyenv/envs/ndenv" export PATH="/Users/kasumi/.anyenv/envs/ndenv/bin:$PATH" export PATH="/Users/kasumi/.anyenv/envs/ndenv/shims:${PATH}" source "/Users/kasumi/.anyenv/envs/ndenv/libexec/../completions/ndenv.bash" ndenv rehash 2>/dev/null ndenv() { typeset command command="$1" if [ "$#" -gt 0 ]; then shift fi case "$command" in rehash|shell) eval "`ndenv "sh-$command" "$#"`";; *) command ndenv "$command" "$#";; esac }
^
from sourcing file -
called on line 60 of file /usr/local/Cellar/fish/2.4.0/share/fish/functions/eval.fish
in function 'eval'
called on line 6 of file ~/.config/fish/config.fish
from sourcing file ~/.config/fish/config.fish
called on standard input
source: Error while reading file '-'
Added:
I tried answer (https://stackoverflow.com/a/42119354/7524270) but I get some new errors.
New Errors:
Variables cannot be bracketed. In fish, please use "$PATH".
- (line 1): begin; source "/Users/kasumi/.anyenv/libexec/../completions/anyenv.fish" function anyenv set command $argv[1] set -e argv[1] command anyenv "$command" $argv end set -x NDENV_ROOT "/Users/kasumi/.anyenv/envs/ndenv" set -x PATH $PATH "/Users/kasumi/.anyenv/envs/ndenv/bin" export PATH="/Users/kasumi/.anyenv/envs/ndenv/shims:${PATH}" ndenv rehash 2>/dev/null ndenv() { typeset command command="$1" if [ "$#" -gt 0 ]; then shift fi case "$command" in rehash|shell) eval "`ndenv "sh-$command" "$#"`";; *) command ndenv "$command" "$#";; esac }
^
from sourcing file -
called on line 60 of file /usr/local/Cellar/fish/2.5.0/share/fish/functions/eval.fish
in function 'eval'
called on line 4 of file ~/.config/fish/config.fish
from sourcing file ~/.config/fish/config.fish
called during startup
source: Error while reading file '-'
Quick fix:
In ~/.config/fish/config.fish, change:
eval (anyenv init -)
to:
eval (anyenv init - fish)
EDIT: or a slightly more bullet-proof approach:
eval (command anyenv init - fish)
(command forces fish to ignore functions)
What's going on?
anyenv init uses the $SHELL environment variable to determine your active shell and returns some commands, to be executed by the shell, in order to finish the initialization of anyenv.
For some reason the $SHELL variable in your environment points to bash and not to fish (you can verify this by running echo $SHELL).
The most probable reason is that fish is simply not the default shell for your user. You may execute grep $USER /etc/passwd to find out (look at what it says after the last :). It's possible to change the default shell with chsh, but if you decide to do it, do it with great care. There might be some important settings in your .bashrc or some other programs may depend on a POSIX-compliant shell to work properly.
Another option is that somewhere you have an override of the $SHELL variable, such that it points to bash and not fish. I have this in my byobu/tmux configuration because it helped me avoid some strange behavior.
Luckily, anyenv init lets the user (you) specify the shell manually (ignore $SHELL), and that should fix your issue with anyenv.

-bash ruby command not found

Every time I log into my VPS I must run source ~/.bashrc before I can run any rvm, ruby, or gem commands.
Why is this? Can't make it load by default?
ssh deployer#xxx
ruby -v
-bash: ruby: command not found
source ~/.bashrc
ruby -v
ruby 1.9.3p429 (2013-05-15 revision 40747) [i686-linux]
I installed rvm under deployer.
I have ~/.bash_pofile which is empty. I also have ~/.profile which has the following in it:
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
My ~/.bashrc has this at the top:
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
From the bash 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 executes commands from the first one that exists and is readable.
So in your case, the (empty) ~/.bash_profile is being executed, and your ~/.profile (and thus your ~/.bashrc) are ignored. To solve this, you'll either need to delete your ~/.bash_profile, or else move the contents of ~/.profile into ~/.bash_profile.
When you log in, if Bash can find a file named .bash_profile in your home directory it will execute it and do not even search for a .profile file. Thus you have two choices, either remove the empty .bash_profile file or copy the contents of .profile to .bash_profile.
Moving the information from .bashrc to the other files, as suggested by others is one way to do it.
Otherwise, this snippet of code will do the same thing, without needing to move the contents, or remove the file. Depending on the ways you have things set up, you may not want to delete a file, if it has relevant information in it for other tasks, other than interactive login.
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
Though using the files as they are intended to be used by reading the documentation can definitely alleviate some frustration.

Adding a function to /etc/profile causes gnome to restart after login

I recently added the following bash function definition to my /etc/profile in Ubuntu 11.04 (it's a function to shortcut a CD command to a specific development directory):
################## JMOZTELEPORT BEGIN ##################
function JMozTeleport() {
version=0.4.58
pathtopythonpackages=`python -c "from site import getsitepackages; print getsitepackages()[0]"`
pathtopythonteleport="$pathtopythonpackages/JMozTools-$version-py2.7.egg/JMozTools/JMozTeleport.py"
# $1 is the command to run
isversion=0
ishelp=0
if [[ "$1" == "-v" || "$1" == "--version" ]]
then
isversion=1;
fi
if [[ "$1" == "-h" || "$1" == "--help" ]]
then
ishelp=1;
fi
if [ -z $1 ]
then
python "$pathtopythonteleport" "-h"
elif [ $1 == "version" ]
then
echo $version
elif [ $isversion == 1 -o $ishelp == 1 ]
then
python "$pathtopythonteleport" "$#"
else
cd $(python "$pathtopythonteleport" "$#")
fi
}
################### JMOZTELEPORT END ###################
Once I do this, though, (which works fine if I source /etc/profile from a terminal shell), I am unable to login to Gnome. It logs in ok, but then it immediately closes Gnome and brings me back to the login screen. If I remove this stuff from my /etc/profile, it again allows me to login fine.
I'm confused as to what is causing this to make gnome restart. Any ideas as to where the problem is?
/etc/profile is sourced by /bin/sh, something that probably happens during Gnome startup. It's probably choking on the [[ ... ]] syntax, which is bash-specific. (/bin/sh may or may not be a symlink to /bin/bash, depending on the system).
Since your function appears to be bash-specific, you might consider putting it in /etc/bash.bashrc rather than /etc/profile, or perhaps even $HOME/.bashrc. (Do you need it in non-interactive shells?)
You put it under debug and see what is causing it to restart. Use, the set -x command to enable debug mode. Similarly the set +x command disables it.
Putting set -x at the top of your /etc/profile should cause debug information to be printed out.

ssh command execution doesn't consider .bashrc | .bash_login | .ssh/rc? [duplicate]

This question already has answers here:
Why aliases in a non-interactive Bash shell do not work
(4 answers)
Closed 6 years ago.
I am trying to execute a command remotely over ssh, example:
ssh <user>#<host> <command>
The command which needs to be executed is an alias, which is defined in .bashrc, e.g.
alias ll='ls -al'
So what in the end the following command should get executed:
ssh user#host "ll"
I already found out that .bashrc only gets sourced with interactive shell, so in .bash_login I put:
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
and I also tried to define the alias directly in .bash_login.
I also tried to put the alias definition / sourcing of .bashrc in .bash_profile and also in .ssh/rc. But nothing of this works.
Note that I am not able to change how the ssh command is invoked since this is a part of some binary installation script. The only thing I can modify is the environment. Is there any other possibility to get this alias sourced when the ssh command is executed? Is there some ssh configuration which has to be adapted?
From the man pages of bash:
Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt
There are a couple ways to do this, but the simplest is to just add the following line to your .bashrc file:
shopt -s expand_aliases
Instead of:
ssh user#host "bash -c ll"
try:
ssh user#host "bash -ic ll"
to force bash to use an "interactive shell".
EDIT:
As pointed out here about non-interactive shells..
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
# execution returns after this line
Now, for every alias in your bashrc file say i have:
alias ll="ls -l"
alias cls="clear;ls"
Create a file named after that alias say for ll:
user#host$ vi ssh_aliases/ll
#inside ll,write
ls -l
user#host$ chmod a+x ll
Now edit .bashrc to include:
# If not running interactively, don't do anything
[ -z "$PS1" ] && export $PATH=$PATH:~/ssh_aliases
This does the job.. although I am not sure if it is the best way to do so
EDIT(2)
You only need to do this for aliases, other commands in bashrc will be executed as pointed out by David "you must have executable for ssh to run commands".
an alternative to alias that will be visible in all script is
EXPORT & EXECUTE VARIABLE
# shortcut to set enviroment to insensitive case
export go_I="shopt -s nocasematch"
Now in any script you can use
#!/bin/bash
$go_I # go Insensitive
[[ a == A ]] # evaluates TRUE ( $? == 0)
$go_C # maibe want to go back to casesensitive
it's useful to place all shortcuts/aliases in /path/to/my_commands and edit /etc/bash.bashrc
source /path/to/my_commands
Open file ~/.bash_profile. If this file does not exist create one in the home directory and add the below line
source = $HOME/.bashrc
exit your ssh and login agian and you should get the .bashrc settings working for you.

Resources