What starts new subshell in Bash? - bash

Are there actions in Bash other than pipes and command substitution that start a new subshell?

Putting a command chain in parens (( ... )) also starts a new subshell.
( cd /tmp ; pwd ) ; pwd

Each shell script running is, in effect, a subprocess (child process) of the parent shell.
A shell script can itself launch subprocesses. These subshells let the script do parallel processing, in effect executing multiple subtasks simultaneously.
say you have script test.sh. After you run it if you run the command
ps -ef|grep -i test.sh
you will see the it runs with different PID
In general, an external command in a script forks off a subprocess/subshell

Related

Multiple running bash script 1 command line?

how to run multiple bash scripts in 1 bash command ?
i use command
bash script1.sh
how to make it run multiple commands in 1 command ?
for example
bash script1.sh bash script2.sh bash script3.sh bash script4.sh
Please help
If you want to run all bash script in //:
for i in {1..4}; do bash "script${i}.sh" & done
If you put the control operator & at the end of a command, e.g. command &, the shell executes the command in the background in a subshell. The shell does not wait for the command to finish, and the return status is 0. Pid of the last backgrounded command is available via the special variable $!
If instead you want to run sequentially, use
printf '%s\n' script{1..4}.sh | xargs -n1 bash
or
for i in {1..4}; do bash "script${i}.sh"; done

What's the effect of combining exec and & in shell script?

I maintained some legacy Linux shell script codes, and I met something like this:
#!/bin/sh
foo()
{
exec some_shell_command &
return 0
}
foo
I'm very curious about the effect of such shell scripts. Is some_shell_command executed in another subprocess? And after the execution of exec command, does shell script process become the some_shell_command process?
Thanks in advance.
update:
The script is:
exec /mnt/usr/bin/pppd $DIAL_DEV unit $count call $PROVIDER ipparam $PROVIDER &
and at sometime:
# Shutdown ppp connection.
pppOff() {
# Get device index.
local index=$1
# Check connection.
pppCheck $index
if [ $? -ne 0 ]; then
echo "invalid pppd: "$index
return 1
fi
# Get pid.
local PID=$PPPD_PID
echo "pppd pid for "$index": "$PID
# Kill
kill -TERM ${PID}
return 0
}
after executing the pppOff, the script itself is killed. So pppd is executed as the same process as the script maybe.
Is some_shell_command executed in another subprocess?
Yes.
after the execution of exec command, does shell script process become the some_shell_command process?
There are two processes, the one spawned for the background becomes some_shell_command. Parent continues execution.
does it mean 'exec' is meaningless?
It has very little meaning in this specific context. Generally, you should expect that Bash optimizes and if Bash finds out there is only one command, it will optimize it to an exec.
$ strace -ff bash -c '/bin/echo 1' 2>&1 | grep clone
# nothing, because `fork()` is optimized out
There are cases (see https://github.com/bminor/bash/blob/f3a35a2d601a55f337f8ca02a541f8c033682247/builtins/evalstring.c#L441 https://github.com/bminor/bash/blob/f3a35a2d601a55f337f8ca02a541f8c033682247/builtins/evalstring.c#L124 ) where the command is not optimized, mostly in the case of like trap or some signal handling that Bash needs to execute after the command is done.
Another difference is that exec requires specifically an executable, where without exec then some_shell_command could be a built-in, function or an alias.

Why does a subshell of an interactive shell run as an interactive shell?

With my Bash session, I run this command:
(echo $$ $BASHPID $-)
and I get
22108 25602 himBH
So, my subshell runs as an interactive shell.
If I try to run the same command in background
(echo $$ $BASHPID $-) &
I get the same output. Why does the subshell run as an interactive shell?
A subshell inherits all the characteristics of the parent, and that includes settings. That's part of the definition of a subshell. It makes no difference if it is running in foreground or background - jobs can be swapped between foreground and background quite easily.
A non-subshell will not be interactive. For example, if I put
(echo $$ $BASHPID $-)
into a script called gash.sh and call it from a non-interactive shell:
$ bash gash.sh
73879 73880 hB
But if I source the file, then it is a subshell of an interactive shell:
$ . ./gash.sh
1130 himBH

command invoking new shell and script is broken

I have two commands:
/aka/ball/barry/pet elephant/rhino
which invoke new shell and I have command
cleartool setview "/view/epp/lpp/tpp.sh" $VIEW
which also invoke new shell. Is it possible to run both in a single script one by one?
Probably; although it depends. If these shells are designed to be interactive, you can still probably make them work by sending them commands to end the subshells, such as exit 0:
$ /aka/ball/barry/pet elephant/rhino <<< 'exit 0'
If that successfully exits the shell, you can just do it in serial:
#!/bin/bash
##
# Your script?
…stuff
/aka/ball/barry/pet elephant/rhino <<< 'exit 0'
cleartool setview "/view/epp/lpp/tpp.sh" "$VIEW" <<< 'exit 0'
…morestuff
Without knowing more about the nature of the shells these programs invoke, it's hard to say for sure.

Entering cshell from bash

I have a bash script and need to run some commands in cshell inside it.
#!/bin/bash
echo entering_to_cshell
csh
echo in_cshell
exit
echo exited_from_cshell
Why doesn't this script run as expected? It only prints entering_to_cshell and it doesn't exit from cshell.
By using
csh
you start a new subshell where your script isn't executed. That's why none of your following commands are executed. Your script waits for this subshell to end which, as you noted, never happens.
Try
csh -c "echo in_cshell"
This way you don't create a new subshell which isn't impacted by your script.
By simply calling csh in your script, you're starting an interactive csh subshell. You'll notice that once you quit from the csh session, your script will then continue to with the subsequent echo and quiting on exit.
To pass a series of commands to csh from you bash script, one approach would be to use the Here Document syntax to redirect commands to csh.
#!/bin/bash
echo entering_to_cshell
csh <<EOF
echo in_cshell
exit
EOF
echo exited_from_cshell
The lines between the EOF entries will be treated as a script that is interpreted by csh.

Resources