(1) how the shell executes a command
There are two types of Linux commands: One is the shell's built-in command, and the other is a shell-independent command. Don't forget, the shell is just a program in the system, when it executes a non-built command, it is essentially calling another program, such as LS. Verify below:
M@meng: ~/scripts$ Which SH/BIN/SHM@meng: ~/scripts$ file/bin/sh/bin/SH:Symbolic link to ' dash ' m@meng: ~/scripts$ file/bin/dash/bin/Dash: ELF +-bitLSBShared Object,Intel 80386, version1(SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6. -,Buildid[sha1]=1fff1896e5f8db5be4db7b7ebab6ee176129b399, STRIPPEDM@meng: ~/scripts$ file/bin/ls/bin/ls: ELF +-bitLSBExecutable,Intel 80386, version1(SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6. -,Buildid[sha1]=25210dc46cdefbe29cf3d2b5ceef3eceb6e2a57e, stripped
This code illustrates two issues: the SH default link in Ubuntu is dash;dash and LS is two independent elf files, you can execute the file, which means that the status of both is equal. From the source point of view, they all have their own main function, compiled into the binary has its own _start entrance. So, to execute the LS command in the shell, the shell needs to build another process, called fork (), and then calls exec () to execute the LS code in the new process.
But for the built-in command, the shell executes a function called itself, which calls its own part of the code, which obviously eliminates the need to create a new process. The shell should have a way of distinguishing which commands are built-in and which are not. For humans, the way to differentiate is to use the which command, where the program files are not found in the built-in command:
m@meng:~/scripts$ which cdm@meng:~/scripts$ which which /usr/bin/whichm@meng:~/scripts$ man cd没有 cd 的手册页条目
CD turned out to be built-in command ... And the built-in command doesn't have a man handbook! The manual for viewing the built-in commands should use the Man builtins command.
(2) how the shell executes a script
As we all know, there are two common ways to execute a shell script: 1, SH script.sh 2, chmod +x script.sh &&./script.sh
The first approach does not require the script to have executable permissions, and can be added after the sh a variety of options for debugging, the principle is to create a new process, execute SH in the new process, while the script file as a parameter to sh, by the SH line read the script command, and then the same as the above to execute the command. But I'm also curious: Why not execute the script directly from the current shell? Why bother creating a new one? Now we'll know.
The second approach requires that the script be given executable permissions (which is probably the key difference between the two approaches, what does executable access mean?). ), and then seemed to be executed directly when the elf file was given ... It's like executing./a.out, what's the situation? Then we're going to introduce the concept of shebang.
The first line of the shell script is often the beginning of this:
#!/bin/bash
"#!" Known as Shebang, this is the standard starting line for shell scripts, which is generally written in the first line. Its role is to indicate the program used to execute the script, note that the program behind Shebang must use an absolute path, and not necessarily a shell such as sh, dash, CSH, or any executable file, such as SED, RM command , or an executable script file, .
with Shebang, the direct execution of the script is as follows (excerpt from Linux C one-stop programming):
The shell will fork a child process and call exec to execute it./script.sh this program, exec The system call should replace the code snippet of the process with the code snippet of the./script.sh program and execute it from its _start. However, script.sh is a text file, there is no code snippet and _start function, what to do? In fact, there is another mechanism of exec, if you want to execute a text file, and the first line with shebang specifies the interpreter, then use the code snippet of the interpreter program to replace the current process, and executes from the _start of the interpreter, and the text file is passed to the interpreter as a command-line argument.
to a chestnut:
m@meng:~/tmp$ lsonlyme tesh.shm@meng:~/tmp$ #!/bin/rm -f$0m@meng:~/tmp$ ./tesh.sh m@meng:~/tmp$ lsonlyme
Test.sh's content is to delete itself, its shebang in the execution program is rm-f, and the script itself, so after the script executes, it disappears ...
So, what happens if the execution procedure in the shebang is not reliable or there is no shebang at all, and the second method is hard to execute?
+ Interpreter does not have permission to execute
m @meng :~/tmp $ ls-l onlyme-rw-rw-r--1 m 6 6 month 23 01 : 22 Onlymem @meng :~/tmp $ Cat test.sh #!/home/m/tmp/onlyme ps-ef | grep $$ | Grep-v grep | Grep-v psm @meng :~/tmp $ ./test.sh bash: ./test. sh: /home/m/tmp/onlyme: Interpreter Error Insufficient permissions
The result was an error.
- Interpreter has executable permission, but the content is not reliable
M@meng: ~/tmp$ LS Onlyme-l-rwxrwxr-x1Mm6 6Month at on: AOnlymem@meng: ~/tmp$ Cat Onlyme Hellom@meng: ~/tmp$ Cat test.sh#!/home/m/tmp/onlymePs-ef | Grep$$| Grep-v grep | Grep-v PSM@meng: ~/tmp$ ./test.sh m31054 5944 0 Geneva: -pts/ - xx:xx:xxBash
The expected error does not appear, but the script can execute normally. This is because the parent shell takes over the script when the interpreter does not execute properly (with Execute permissions). The parent shell is the shell where the script was entered, and we can verify that:
m@meng:~/tmp$ sh$ /home/m/tmp/test.shm 3109331091 003:03 pts/14 00:00:00 /bin/sh /home/m/tmp/test.sh
The input SH enters the sh world, the current shell is no longer bash, then executes the script (the content remains the same as the shell used by the current process), and the shell that makes the interpreter has become/bin/sh.
- Interpreter does not exist
root@meng:/home/m/tmp# lsonlyme test.shroot@meng:/home/m/tmp# cat test.sh #!/home/m/tmp/onlyme2$SHELLroot@meng:/home/m/tmp# ./test.sh bash: ./test.sh: /home/m/tmp/onlyme2: 解释器错误: 没有那个文件或目录
M@meng: ~/tmp$ Cat test.sh Ps-ef | Grep$$| Grep-v grep | Grep-v PSM@meng: ~/tmp$ ./test.sh m30534 5944 0 Geneva: -pts/ - xx:xx:xxBashm@meng: ~/tmp$ Sh$ /home/m/tmp/test.shm30551 30550 0 Geneva: -pts/ - xx:xx:xx/bin/sh/home/m/tmp/test.sh
Same as the result of the second case: the parent shell took over.
- Interpreter specified when executing script
m@meng:~/tmp$ cat test.sh \#!/bin/bash$$ | grep -v grep | grep -v psm@meng:~/tmp$ dash test.sh m 30610 5944 002:24 pts/14 00:00:00 dash test.sh
Obviously, the interpreter specified when executing the script overwrites the contents of the shebang.
(3) temporary script in the command line
If you do not want to write some of the command combination into a file to execute (a little trouble), and this combination is not necessary for long-term preservation, but temporary use, you can use a semicolon to put a bunch of commands on one line and then execute:
m@meng:~/tmp$ lsonlyme test.shm@meng:~/tmp$ cd ..;lsblog new program test.sh tmp wine-git 公共的 视频 文档 音乐examples.desktop patches scripts timerecords VirtualBoxVMs workspaces 模板 图片 下载 桌面
The advantage of this is that if the first command takes a long time, then using a semicolon will not have to wait for it to finish before entering the second command. You can enter the second command in advance, and then execute the second one automatically when the first command finishes.
However, this is not enough to be scripted because these commands change the environment of the parent shell, such as the CD command. The real script is executed in a new process, and returning to the parent shell after execution does not change the environment of the parent shell. To achieve this, you need to enclose these command combinations in parentheses:
m@meng:~/tmp$ (cd ..;ls)blog new program test.sh tmp wine-git 公共的 视频 文档 音乐examples.desktop patches scripts timerecords VirtualBoxVMs workspaces 模板 图片 下载 桌面m@meng:~/tmp$ lsonlyme test.sh
Sure enough to achieve the effect of the script ~
But there is a drawback to this approach: the length is limited. The length of a single command that the shell can accept is limited, but is generally sufficient.
Execution of the script for the Linux shell