When we talked about the number of scripts being executed in CU a few days ago, we found that we knew little about how to execute commands in shell... thank you for your advice! In addition to being inaccurate in some places, his statement is basically correct. I took the time to find some materials to study these days and learned a lot! Here, I am able to post my thoughts in the form of Q & A for your reference. The younger brother is too easy to learn. There must be many mistakes. You are welcome to shoot bricks and correct yourself!
Q1: How does shell execute the "simple" command?
A: The simple commands here have the same meanings as those in the bash reference manual. Generally, the form is: the command name and its parameters. There are three different simple commands:
1. built-in commands (builtin)
It is built-in by shell interpreter and directly executed by shell, and no new process needs to be derived. Some internal commands can be used to change the current shell environment, such:
cd /pathvar=valueread varexport var...
2. external commands ("external command" or "disk command ")
The binary executable file needs to be loaded into memory by the disk for execution. A new process is derived. The shell interpreter calls a copy of fork itself and then uses the exec Series Function to execute External commands. Then, the external command replaces the subshell of the previous fork.
3. shell script)
The shell interpreter fork + exec executes this script command. In the exec call, the kernel checks the first line of the script (for example :#! /Bin/sh), find the interpreter used to execute the script, and then load the interpreter to explain and execute the script program. There may be many kinds of interpreter programs, various shell (Bourne shell, Korn shell cshell, rc and its variants ash, dash, bash, zshell, pdksh, tcsh, es ...), awk, tcl/tk, regular CT, perl, python, and so on. The program is obviously a sub-process of the current shell. If this interpreter is the same shell as the current shell, such as bash, It is the subshell of the current shell, and all the commands in the script are executed in the subshell environment, does not affect the current shell environment.
Q2: Is the shell script executed as a separate process?
A: No. The shell script itself cannot be used as A process. As mentioned above, shell scripts are interpreted and run by a shell interpreter. This shell interpreter is a separate process, and the external commands in the script are also run as independent processes in turn. This is why ps cannot find the name of the running script. As an alternative, you can call the script as follows:
sh script-name
In this case, the shell interpreter "sh" is explicitly called as an external command, and the script-name as the command line parameter of this command can be ps.
In addition, if the pidof command is available on your system, it can find out the process ID of the shell script process (actually the sub-shell process that executes the shell script:
pidof -x script-name
Q3: When will shell execute commands in the subshell?
A: Here we will mainly discuss the Bourne shell and its compatible shell. In many cases, the shell will execute the command in the sub-shell:
1. (...) Structure
Commands in parentheses are executed in a sub-shell environment, and the execution result does not affect the current shell environment. Note that the variable $ displays the process id of the Current shell, rather than the process id of the sub-shell.
Refer to the command in the {...;} structure to execute in the current shell. The (internal) command execution result will affect the current shell environment.
2. Background execution or asynchronous execution
Command & command is executed by a sub-shell in the background. The current shell gets control immediately and waits for user input. The background commands are executed in parallel with the current shell, but there is no mutual dependency or waiting relationship, so it is asynchronous parallel.
3. Command replacement
Command '(Bourn shell and compatible shell/csh), $ (command) (available in ksh/bash/zsh) Replace the standard output of command execution with the current command line. Command is executed in the sub-shell environment, and the result does not affect the current shell environment.
4. Pipelines (different shell processes are different)
Cmd1 and cmd2 run in parallel and are dependent on each other. The standard input of cmd2 comes from the standard output of cmd1, and the two are "synchronized. Different shell implementations for MPs queues are implemented in different ways. In linux, most shells (bash, pdksh, ash, and dash, except for zshell) execute all the commands in the pipeline in the subshell environment, the command execution result does not affect the current shell environment.
A newer version of The Korn shell (after ksh93) is special. The command at the last level of the MPs queue is executed in the current shell. This is a feature, not a BUG, which is also allowed in the POSIX standard. This makes the following command structure possible:
command|read var
Since read var (read is an internal command) is executed in the current shell, the var value is available in the current shell. Otherwise, the read var in bash/pdksh/ash/dash is executed in the sub-shell environment. The value read by var cannot be passed to the current shell, so the var variable cannot get the expected value. Questions like this are frequently asked in various forums and news groups. I personally think that the structure of command | read var is clear and logical, so I think this feature of Korn shell is very good. Unfortunately, not all shells are implemented in this way. (For example, the open-source pdksh is used to execute each level of commands in the sub-shell pipeline.
Another special feature of the Korn shell processing pipeline is that if the pipeline is executed in the background, the command before the pipeline will be derived from the command at the last level, rather than from the current shell. It is said that the Bourne shell also has this feature (the standard Bourne shell does not have a test environment, and interested friends can verify it on their own if they have the conditions ). But their open-source imitators, pdksh and ash, do not.
The most special is zshell. A newer zshell implementation (as if at least 3.0.5 or above) will execute each level of commands in the pipeline in the current shell, not just the last one. Each Command is derived from the current shell and executed in the background. It can be seen that executing pipeline commands in sub-sehll is not a last resort, probably because the implementation is convenient or such processing has become one of the unix traditions .; -)
Let's sum up that different shells may have different processing methods for pipeline commands. In some shell, the structure of command | read var is OK, but our code cannot depend on this for compatibility reasons. It is best to avoid similar code.
5. Process replacement (only in bash/zsh, not POSIX compatible)
<(...)
> (...)
Similar to pipelines, for example, cmd1 <(cmd2)> (cmd3), cmd1, cmd2, and cmd3 are executed in parallel simultaneously.
<(Command) can be used in any command line where the input file name needs to be filled in. The standard output of command is read by this command as an input file.
> (Command) can be used in any command line where the output file needs to be filled in. The output of this command will be read by command as the standard input. Both commands are executed in the sub-shell environment, and the result does not affect the current shell environment.
6. if or while command block input/output redirection
In the Bourne shell of SVR4.2, this situation will fork a sub-shell to execute the commands in the if block and while block; in linux, it seems that other shells do not.
7. coroutine (ksh)
Only the Korn shell and pdksh have a mechanism for coworking processes (other shells can be simulated using named pipelines ). Similar to common background commands, the coroutine runs synchronously in the background, so it must be run in the sub-shell. Different from the background commands, the coroutine process interacts with the foreground process (using read-p and print-p), while the latter simply runs asynchronously.
Q4: What is the difference between executing a command in the current shell and executing a command in the subshell?
A: This statement is not accurate.
Executing Internal commands in the current shell does not dispatch a child shell, so some internal commands can change the current shell execution environment.
When executing external commands or scripts in the current shell, the execution of the commands will not affect the current shell environment. Note: The Internal commands executed in the sub-shell will only change the execution environment of the sub-shell, but will not change the environment of the Current shell (parent shell.
Q5: how to send the variables in the sub-shell back to the parent shell?
A: For example (echo "$ a") | read B cannot work. How can I find an alternative? The following are some possible solutions:
1. Use temporary files
...#in subshella=100echo "$a">tmpfile...#in parentread b
2. Use Named Pipes
mkfifo pipef(...echo "$a" > pipef...)read b
3. Use coprocess (ksh)
( echo "$a" |&)read -p b
4. Use commands to replace
b=`echo "$a"`
5. Run the eval command
eval `echo "b=$a"`
6. Use the here document
read b <`echo "$a"`END
7. Use here string (bash/pdksh)
read b <<<`echo "$a"`
8. Run the. Or source command to execute the script without using a sub-shell.
That is, execute scripts in the Current shell environment. If there is no sub-shell, there will be no sub-shell troubles. :)
The solution is more than that. Other means of inter-process communication should also be available, which needs to be explored together. Pai_^