I'm on a Linux machine using screen, and I'm attempting to write a (fairly portable) function which runs a bash function in a new, detached screen session which automatically closes upon completion. I've had some success, but I noticed the following behavior:
If I include the definition of mail_submit() in my ~/.bashrc file, I can run
mail_submit foo
in the terminal, and also I can access the alias in a new screen session:
screen -S test
mail_submit foo
However, the following command does not work:
screen -d -m -S test sh -c 'mail_submit foo'
presumably because sh -c starts a fresh shell that has no knowledge of my ~/.bashrc profile. So, I can use the following fix:
screen -d -m -S test sh -c 'source ~/.bashrc; mail_submit foo'
which does work.
But if I want to wrap this functionality up into a bash alias (which is my ultimate goal here), this will cause a weird self-referential situation.
Question: What is an easy way to either have sh -c know the location of my ~/.bashrc profile, or use a variant of sourcing the file and creating an alias?
EDIT: I could save the shell script in my home directory, and create an alias which runs
screen -d -m -S test bash -c '~/mail_submit.sh $1'
but I'd still be curious to hear other possible fixes.
A default ~/.bashrc contains this ([[ "$-" != *i* ]] && return) little piece of code on top of it (or somewhere else in the upper part). This line will prevent the ~/.bashrc from beeing sourced if the bash shell doesn't run in interactive mode.
You could:
Remove this line
Create a new file which will only contain the alias you need and source that
Create a little bash script instead of an alias and run that
Do you mean screen -d -m -S test bash -c 'mail_submit foo'?
It looks like you're trying to run the command with the shell (sh), and not the bourne again shell (bash), which is the shell interpreter which actually reads the ~/.bashrc profile.
Edit: The .bashrc file is not being sourced by default because screen does not create the bash process as a login shell, which is when the .bashrc file is read. Creating a .screenrc file with the line defshell -bash will create the bash process as a login shell instead, which will then call the .bashrc file.
Related
I'm making a small edit to a shell script I use to mask password inputs like so:
#!/bin/bash
printf "Enter login and press [ENTER]\n"
read user
printf "Enter password and press [ENTER]\n"
read -s -p pass
With the read -s -p pass being the updated part. For some reason I'm not seeing the changes when I run it normally by entering script.sh into the command line but I do see the changes when I run sh script.sh. I've tried opening new terminal windows, and have run it in both ITerm and the default Mac terminal. I'm far from a scripting master, does anyone know why I'm not seeing the changes without the prefix?
Use a full or relative path to the script to make sure you're running what you think you're running.
If you are running it as simply script.sh then the shell will PATH environment variable lookup to locate it. To see which script.sh bash would be using in that case, run type script.sh.
Relative Path
./script.sh
Full Path
/path/to/my/script.sh
I'm very confused about how my shell is reading bash_profile.
In root, my ~/.bash_profile looks like so
# .bash_profile
# Get the aliases and functions
if [-f ~/.bashrc ]; then
.~/.bashrc
fi
PATH=$PATH:$HOME/bin:$HOME/sbin:$HOME/usr/sbin:$HOME/usr/bin:/usr/sbin
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
export PATH=$PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
unset USERNAME
There is no ~/.profile file.
In a user called maruhan, my ~/.bash_profile looks like so
# .bash_profile
# Get the aliases and functions
if [-f ~/.bashrc ]; then
.~/.bashrc
fi
PATH=$PATH:$HOME/bin:$HOME/sbin:$HOME/usr/sbin:$HOME/usr/bin:/usr/sbin
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/maruhan/Desktop/issac:/usr/local/lib
ASDF=$ASDF:/home
export PATH=$PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
export ASDF=$ASDF
unset USERNAME
And my ~/.profile looks like so
LD_LIBRARY_PATH=/home/maruhan/Desktop/issac:/usr/local/lib:$LD_LIBRARY_PATH
ASDF=/home:$ASDF
export ASDF=$ASDF
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
You can clearly see that ASDF is not defined in root's bash_profile.
However when I call export, I get this in root.
declare -x ASDF=":/home"
but nothing about LD_LIBRARY_PATH.
Strangely in maruhan, running export shows both ASDF and LD_LIBRARY_PATH.
Also, nothing about ASDF or LD_LIBRARY_PATH exist in /etc/environment. I also don't have a /etc/bash_profile file.
Running echo $0 gives me bash for both root and maruhan.
How come LD_LIBRARY_PATH disappeared in root while ASDF is there?
The rules are a bit complicated. According to bash's man page:
INVOCATION
A login shell is one whose first character of argument zero is a -, or one
started with the --login option.
An interactive shell is one started without non-option arguments (unless -s is
specified) and without the -c option whose standard input and error are both
connected to terminals (as determined by isatty(3)), or one started with the -i
option. PS1 is set and $- includes i if bash is interactive, allowing a shell
script or a startup file to test this state.
... ...
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.
... ...
When an interactive shell that is not a login shell is started, bash reads and
executes commands from ~/.bashrc, if that file exists. This may be inhibited by
using the --norc option. The --rcfile file option will force bash to read and
execute commands from file instead of ~/.bashrc.
... ...
Note that on some systems bash may be customized so that it would also execute a system wide rc file (e.g. /etc/bash.bashrc) before sourcing ~/.bashrc for an interactive shell that's not a login shell.
Shells started by a login mechanism (usually with a username/password prompt, like console login, telnet, ssh, ...) are usually login shells. For a login shell, $0 is usually -bash.
[local] % ssh user#host <-- The user is trying to login
Password: P#ssw0rd
[remote] % echo $0
-bash <-- This is a login shell
[remote] % bash <-- This is not a login (no username/password)
[remote] % echo $0
bash <-- Not a login shell
[remote] %
To make life easier I would put all rc things in ~/.bashrc and source ~/.bashrc in ~/.bash_profile. For example:
% cat ~/.bash_profile
[[ -f ~/.bashrc ]] && source ~/.bashrc
% cat ~/.bashrc
# return immediately if not in an interactive shell
[[ $- != *i* ]] && return 0
export FOO=bar
PATH=$PATH:/my/path
%
I usually use bash scripts to setup my environments (mostly aliases that interact with Docker), ie:
# ops-setup.sh
#!/bin/bash
PROJECT_NAME="my_awesome_project"
PROJECT_PATH=`pwd`/${BASH_SOURCE[0]}
WEB_CONTAINER=${PROJECT_NAME}"_web_1"
DB_CONTAINER=${PROJECT_NAME}"_db_1"
alias chroot_project="cd $PROJECT_PATH"
alias compose="chroot_project;COMPOSE_PROJECT_NAME=$PROJECT_NAME docker-compose"
alias up="compose up -d"
alias down="compose stop;compose rm -f --all nginx web python"
alias web_exec="docker exec -ti $WEB_CONTAINER"
alias db="docker exec -ti $DB_CONTAINER su - postgres -c 'psql $PROJECT_NAME'"
# ...
I'd like them to be run when I open the embedded terminal.
I tried Startup Tasks but they are not run in my terminal contexts.
Since I have a dedicated script for each of my projects, I can't run them from .bashrc or other.
How can I get my aliases automatically set at terminal opening ?
Today I'm running . ./ops-setup.sh manually each time I open a new embedded terminal.
You can create an alias in your .bashrc file like so:
alias ops-setup='bash --init-file <(echo '. /home/test/ops-setup.sh'; echo '. /home/test/.bashrc')'
If you call ops-setup, it will open up a new bash inside your terminal, and source .bashrc like it normally would, as well as your own script.
The only way I see to completely automate this is to modify the source code of your shell, e.g. bash, and recompile it. The files that are sourced are hardcoded into the source code.
I was trying the below program,
This is a simple script, to cd into a folder
#! /bin/bash
cd /root/
But this below command , doesnt get into the folder
EDITED
#!/bin/bash
alias ex="cd /fs/fm"
alias ex1="source setenv"
alias ex2="cd /fs/fm/tests"
alias ex3="runtest"
To get into /root/ you should make sure that you have permissions. It's accessible if you're running as root itself but if you're running as a normal user you should consider becoming root first. One way is to use sudo:
sudo bash script.sh
And again, make sure your script is in UNIX format. Certainly you can't change to /root/\r.
sed -i 's|\r||' script.sh
dos2unix script.sh
This will never work The script you're running is a separate process, when it finishes you get back to the original environment (cwd, enviroment variables, etc...).
Create an alias:
alias r="cd /root"
or execute the script within your shell:
. myscript
Note: . is a synonym for source.
I have following script:
#!/usr/bin/env bash
# set -xv
tmux new-window -n 'foo' 'source "$HOME/.rvm/scripts/rvm"; sleep 123' \;
On one machine it works perfectly, on the second I got an error:
sh: 1: source: not found
Ofcourse running command from shell works perfectly.
What is wrong? Machines have similar dot files....
source is not a POSIX command. Use . instead. The machine that fails is probably using dash as the system shell, not bash. The fact that tmux is executed from a bash script does not mean bash is used to execute the command given to new-window. tmux will use the system shell /bin/sh, so the command should not rely on non-POSIX features like the source synonym for ..