is it possible to kill/exit the current bash
shell and start a new one with some command?
Something like
kill -9 $PPID && bash -c echo 'I started new!'
which does not work obviously.
You don't kill shells, you kill processes. You can start both processes and commands including shells though.
Starting a process is done by cloning (forking) one.
Starting a command would mean executing it.
Something typically starts a shell (let's say bash) script by forking itself, and in one of the branches of the fork (typically the child) running execve("/path/to/bash", ["bash", "/path/to/the-script"], environ)
.
That process will read the contents of the-script
one line at a time and interpret the shell code in it.
Before doing that, it will initialise a few special parameters including $$
for the pid of the process that executed it, $PPID
for the parent of that process (at that time; that may be the other branch of the fork mentioned above, or that could be pid 1 or that of the child subreaper).
Some of the code it reads will often cause the shell process to spawn more processes (fork itself) in some of which it will execute more commands. After all, a shell is a language interpreter specialised in running commands, and those have to be run in separate processes if you want to be able to run more than one.
For those commands that are shell builtins such as kill
, the shell doesn't need to fork itself to execute them, though.
It is worth noting that in those child processes, $$
and $PPID
remain unchanged, regardless of whether the corresponding processes are still alive or not. They are not the pid and ppid of the shell process that happens to be expanding those parameters, they are the pid and ppid of the process that originally executed the shell interpreter.
So when you do kill -9 $PPID
, that will (as long as $IFS
has not been modified as you forgot to quote that expansion) run the kill
command in the same process, which may or may not be one that originally executed the shell if that code is found as part of a subshell or a pipeline for instance, and send the SIGKILL signal (a signal that cannot be handled and should only be used as a last resort) to whatever the parent process of the one that executed the shell at the time it initialised itself.
That will not kill the shell, though the shell might die as some consequence of its parent dying. For instance, if the parent is a terminal emulator, the shell process(es) might receive a SIGHUP as the terminal hung up.
If you replace it with kill "$$"
, then the process that initially executed the shell in a child of itself and might still be around waiting for that child process, will see it having died and carry on with its own business.
If it's the process with $$
as pid that ran that kill "$$"
, then it will die and won't be able to carry on with bash -c echo 'I started new!'
.
What you can do here though is:
exec bash -c echo 'I started new!'
exec
should rather have been called no-fork
. That tells the current shell process to execute bash
in the same process, not in a child one, so basically that will restart the shell, re-execute it in the same process. That process does not terminate. If it still has a parent waiting for it, that parent will not see its end until that new bash shell calls exit
or gets itself killed.
You could also do:
bash -c echo 'I started new!' & exit
In which case the current shell process runs bash
in a child of itself, but does not wait for its termination and exits straight away.
Then, if it has a parent, that parent will see that shell process terminating but will not be aware of the new bash process (its grandchild).
Sure. As soon as you login to your system, type "bash" to open a new shell on top of your login shell.
Then do whatever you wish to do in that shell environment.
When you're ready to kill that and start "clean" in a new shell, just type "exit", then "bash" again.
exec
builtin?exec
does the running without the forking, so that already works. Feels like a pretty fundamental concept! As Kamil asks, hm, you're asking interesting questions, but it seems you've forgot to give us the "bigger picture", of what you want to achieve that way (hint: most of your environment might simply "survive" that replacement, so whatever you are trying to clean up that way might, too.)