What does this command do? exec bash -l
exec
executes a specified command, replacing the current process rather than starting a new subprocess.
If you type
bash -l
at a shell prompt, it will invoke a new shell process (the -l
makes it a login shell). If you exit that shell process, you'll be back to your original shell process.
Typing
exec bash -l
means that the new shell process replaces your current shell process. It's probably slightly less resource intensive.
The reason for doing it is probably so that the new shell sets up its environment (by reading your .bashrc
, .bash_profile
, etc.).
See the bash documentation for more information:
- Bash Startup Files for how a login shell differs from a non-login shell
- Bourne Shell Builtins for documentation on the
exec
command.
(You should be able to read the manual on your own system by typing info bash
.)
Option -l of exec shell command
The -l
option of exec
adds a -
at the beginning of the name of your command. For example:
exec -l diff | head
-diff: missing operand after '-diff'
-diff: Try '-diff --help' for more information.
Note the -
everywhere before diff
.
The point of all this? If you have a -
before a command to start a shell it will act as a login shell. From man bash
:
A login shell is one whose first character of argument zero is a -, or one started with the --login option.
Now, man exec
states that:
If the -l option is supplied, the shell places a dash at the beginning of the zeroth argument passed to command. This is
what login(1) does.
So exec -l bash
will run bash
as a login shell. To test this, we can use the fact that a login bash executes the file ~/.bash_profile
, so:
$ cat ~/.bash_profile
#!/bin/sh
printf "I am a login shell!\n"
If I start a login bash, the command printf "I am a login shell!\n"
will be executed. Now to test with exec
:
$ exec bash
$
Nothing is displayed, we are on a non-login shell.
$ exec -l bash
I am a login shell!
$
Here we have a login shell.
What is the purpose of using exec command
The exec
is a builtin command of the Bash shell which allows you to execute a command that completely replaces the current process, i.e., the current shell process is destroyed, and entirely replaced by the command you specify. It is useful when you want to run a command, but you don't want a bash shell to be the parent process. When you exec a command, it replaces bash entirely - no new process is forked, no new PID is created, and all memory controlled by bash is destroyed and overwritten. This can be useful if, for instance, you want to give a user restricted access to a certain command. If the command exits because of an error, the user will not be returned to the privileged shell that executed it. exec
may also be used without any command, to redirect all output of the current shell to a file. Here is the definition from man bash:
exec [-cl] [-a name] [command [arguments]]
If command is specified, it replaces the shell. No new process
is created. The arguments become the arguments to command. If
the -l option is supplied, the shell places a dash at the
beginning of the zeroth argument passed to command. This is
what login(1) does. The -c option causes command to be executed
with an empty environment. If -a is supplied, the shell passes
name as the zeroth argument to the executed command. If command
cannot be executed for some reason, a non-interactive shell
exits, unless the exec fail shell option is enabled. In that
case, it returns failure. An interactive shell returns failure
if the file cannot be executed. If command is not specified,
any redirections take effect in the current shell, and the
return status is 0. If there is a redirection error, the return
status is 1.
I don't understand bash exec
Yes, it sends any further output to the file named logfile
. In other words, it redirects standard output (also known as stdout) to the file logfile
.
Example
Let's start with this script:
$ cat >script.sh
#!/bin/bash
echo First
exec >>logfile
echo Second
If we run the script, we see output from the first but not the second echo
statements:
$ bash script.sh
First
The output from the second echo
statement went to the file logfile
:
$ cat logfile
Second
$
If we had used exec >logfile
, then the logfile
would be overwritten each time the script was run. Because we used >>
instead of >
, however, the output will be appended to logfile
. For example, if we run it once again:
$ bash script.sh
First
$ cat logfile
Second
Second
Documentation
This is documented in man bash
:
exec [-cl] [-a name] [command [arguments]]
If command
is specified, it replaces the shell. No new process is created. The
arguments become the arguments to command. If the -l option is
supplied, the shell places a dash at the beginning of the zeroth
argument passed to command. This is what login(1) does. The -c
option causes command to be executed with an empty environment. If
-a is supplied, the shell passes name as the zeroth argument to the executed command. If command cannot be executed for some reason, a
non-interactive shell exits, unless the execfail shell option is
enabled. In that case, it returns failure. An interactive shell
returns failure if the file cannot be executed. If command is not
specified, any redirections take effect in the current shell, and the
return status is 0. If there is a redirection error, the return
status is 1. [Emphasis added.]
In your case, no command argument is specified. So, the exec
command performs redirections which, in this case, means any further stdout is sent to file logfile
.
find command and -exec
The find command has a -exec
option. For example:
find / -type f -exec grep -l "bash" {} \;
Other than the similarity in name, the -exec
here has absolutely nothing to do with the shell command exec
.
The construct -exec grep -l "bash" {} \;
tells find
to execute the command grep -l "bash"
on any files that it finds. This is unrelated to the shell command exec >>logfile
which executes nothing but has the effect of redirecting output.
`shell: bash -l {0}` in GitHub Actions
That could be linked to issue 128 which states:
I got stuck for a while because my run commands were not using a login bash shell.
So the conda environment was not active.Would be helpful to warn about that and recommend something like the following in the yaml:
defaults:
run:
shell: bash -l {0}
With:
-l
to insure a login bash, where the environment is correctly set;{0}
, a template placeholder, replaced at pipeline execution time by the actual script command to execute.
Why do I have to use bash -l -c inside my container?
From bash(1)
:
-l
Make bash act as if it had been invoked as a login shell-c
If the -c option is present, then commands are read from string.
You're running the command passed to the -c
argument. -l
makes it a login shell so bash first reads /etc/profile
, which probably has the path to rvm
which is what makes it work.
FWIW, here's what I do to install rvm
in a docker container.
# Install some dependencies
RUN apt-get -y -q install curl rubygems
# Install rvm
RUN curl -L https://get.rvm.io | bash -s stable
# Install package dependencies
RUN /usr/local/rvm/bin/rvm requirements
# Install ruby
RUN /usr/local/rvm/bin/rvm install ruby-2.0.0
# create first wrapper scripts
RUN /usr/local/rvm/bin/rvm wrapper ruby-2.0.0 myapp rake rails gem
do I add 'exec bash -l' to .cshrc to have bash default shell for ssh session? (or what)
Use chsh
command to change your default login shell.
Print the list of shells available:
chsh -l
Change default shell:
chsh -s /bin/bash <username>
Get the default login shell of the current user:
getent passwd <username> | cut -d: -f7
Bash shebang option -l
The -l
option (according to the man page) makes "bash act as if it had been invoked as a login shell". Login shells read certain initialization files from your home directory, such as .bash_profile
. Since you set the value of TEST
in your .bash_profile
, the value you set on the command line gets overridden when bash
launches.
Execute a command in bash script
There are two ways you can do this. One way would be to set your shell script as
# File: command_execute.sh
$1
and run it like this: sh command_execute.sh 'ls -l'
(notice the single quotes around ls -l
). What this will do is the full string ls -l
will be passed to your script, and since it is the first argument to the script, $1
in the script will be effectively replaced with ls -l
, and then that command will be executed.
The other way would be to use this as your script:
# File: command_execute.sh
"$@"
In this case, "$@"
is all the arguments that were passed to the script. If you run the script like sh command_execute.sh ls -l
(note in this case the ls -l
is not quoted), then ls
is passed to the script as argument 1, and -l
is passed to the script as argument 2. Then "$@"
is effectively replaced with ls -l
, and then the command is executed.
Which of these is best depends on your requirements.
Related Topics
Bash Script to Get All Ip Addresses
What Is This $Path in Linux and How to Modify It
Redirecting Man Page Output to File Results in Double Letters in Words
Difference Between Completion Variables and Semaphores
How to Run Elasticsearch 2.1.1 as Root User in Linux MAChine
How to Change the Soname of a Binary Directly
Determine the Os Version, Linux and Windows from Powershell
Get the Characters After the Last Index of a Substring from a String
When Should Xargs Be Preferred Over While-Read Loops
How to Open a File in Assembler and Modify It
Packet Sniffing Using Raw Sockets in Linux in C
How to Replace Single Quotes with Another Character in Sed
Hook into Linux Key Event Handling
Elf Dynamic Loader Symbol Lookup Ordering
Bash Printf %Q Invalid Directive
Kdevtmpfsi - How to Find and Delete That Miner
Shell Script Printing Contents of Variable Containing Output of a Command Removes Newline Characters