(1) how the shell executes a command
Linux commands fall into two categories: one is the shell's built-in command, and the other is a shell-independent command. Don't forget, the shell is only a program in the system, when it executes a non-built-in command, is essentially calling another program, such as LS. Here's how to verify:
m@meng:~/scripts$ which sh
/bin/sh
m@meng:~/scripts$ file/bin/sh/bin/sh:symbolic
link to ' dash '
m@meng:~/scripts$ file/bin/dash
/bin/dash:elf 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamical Ly linked (uses shared libs), for Gnu/linux 2.6.24, buildid[sha1]=1fff1896e5f8db5be4db7b7ebab6ee176129b399, stripped
m@meng:~/scripts$ file/bin/ls
/bin/ls:elf 32-bit LSB executable, Intel 80386, version 1 (SYSV), Dynamicall Y linked (uses shared libs), for Gnu/linux 2.6.24, buildid[sha1]=25210dc46cdefbe29cf3d2b5ceef3eceb6e2a57e, stripped
This code illustrates two issues: in Ubuntu, the SH default link is dash;dash and LS are two independent elf files that can execute files, which means the status is equal. From the source point of view, they have their own main function, compiled into a binary system has its own _start entrance. So, to execute the LS command in the shell, the shell needs to build another process, call fork (), and then call EXEC () execute the LS code in the new process.
But for built-in commands, the shell executes with a call to one of its own functions, 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 and which are not. For humans, the distinguishing approach is to use the which command, where the program files are not found in the built-in commands:
m@meng:~/scripts$ which CD
m@meng:~/scripts$ which which/usr/bin/which man
cd
No CD's Hand album entry
CD is a built-in command ... And there's no Man handbook for built-in commands. 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 generally two ways to execute a shell script: 1, SH script.sh 2, chmod +x script.sh &&/script.sh
The first approach does not require scripts to have executable permissions, and you can add various options for debugging after SH, the principle is to create a new process, in the process of the execution of SH, while the script file as parameters to the SH, by SH-line read the commands in the script, and then as the above execution command. But I'm also curious: Why not execute the script directly from the current shell? Why bother to create a new one. Now we'll know.
The second option is to give the script executable permissions (which is likely to be the key difference between the two approaches, and what it means to execute permissions.) And then it appears that directly when the elf file was executed ... Just like the execution of./a.out, this is what the situation is. And then we're going to introduce the concept of Shebang ~
The first line of a shell script often starts like this:
#!/bin/bash
“#!” Called Shebang, this is the standard starting line for the shell script, which is usually written in the first line. Its role is to indicate the program that is used to execute the script, and note that the program behind the shebang must use an absolute path and not necessarily a shell such as sh, dash, CSH, or any executable file, such as SED, RM. , or an executable script file.
With Shebang, the principle of direct execution of the script is this (excerpt from Linux C one-stop programming):
The Shell fork a subprocess and invokes exec execution./script.sh This program, the EXEC system call should replace the code snippet of the process with the code snippets of the./script.sh program and start execution from its _start. However, script.sh is a text file, there is no code snippets and _start functions, how to do? In fact, exec also has another mechanism, if you want to execute a text file, and the first line with shebang specified interpreter, then the interpreter program's code snippet replaces the current process, and executes from the _start of the interpreter, and this text file is passed to the interpreter as a command-line argument.
Here's a chestnut:
m@meng:~/tmp$ ls
onlyme tesh.sh
m@meng:~/tmp$ cat tesh.sh
#!/bin/rm-f
$
m@meng:~/tmp$./ tesh.sh
m@meng:~/tmp$ ls
onlyme
Test.sh's content is to delete itself, its shebang in the execution of the program is Rm-f, and $ represents the script itself, so after the script execution, it disappeared ...
So, what happens if the execution program in the shebang is not reliable or there is no shebang at all, and it is hard to execute with the second method. Interpreter does not have executable permissions
m@meng:~/tmp$ ls-l onlyme
-rw-rw-r--1 m M 6 June 01:22 onlyme m@meng:~/tmp$
cat test.sh
#!/home/m/tmp/o Nlyme
ps-ef | grep $$ | grep-v grep | grep-v ps
m@meng:~/tmp$/test.sh
bash:./test.sh:/home/m/tmp/onlyme : Interpreter Error: Insufficient permissions
The result was an error. The interpreter has executable permissions, but the content is not reliable
m@meng:~/tmp$ ls onlyme-l
-rwxrwxr-x 1 M 6 June 01:22 onlyme
m@meng:~/tmp$ cat onlyme
Hello
m@me ng:~/tmp$ cat test.sh
#!/home/m/tmp/onlyme
ps-ef | grep $$ | grep-v grep | grep-v ps
m@meng:~/tmp$./tes t.sh
m 31054 5944 0 02:59 pts/14 00:00:00 Bash
The expected error does not occur, but the script can execute normally. This is because when the interpreter is not performing properly (with Execute permissions), the parent shell takes over the script. The parent shell is the shell where the script is entered, and we can verify that:
m@meng:~/tmp$ sh
$/home/m/tmp/test.sh
m 31093 31091 0 03:03 PTS/14 00:00:00/bin/sh/home/m /tmp/test.sh
Input sh into the SH world, the current shell is no longer bash, then execute the script (the content does not change, or show the current process using the shell), found that the interpreter shell has become a/bin/sh. Interpreter does not exist
root@meng:/home/m/tmp# ls
onlyme test.sh
root@meng:/home/m/tmp# cat test.sh
#!/home/m/tmp/onlyme2
echo $SHELL
root@meng:/home/m/tmp#./test.sh
bash:./test.sh:/home/m/tmp/onlyme2: Interpreter Error: No file or directory
There is no shebang this line
m@meng:~/tmp$ cat test.sh
ps-ef | grep $$ | grep-v grep | grep-v ps
m@meng:~/tmp$./test.sh
m 30534
5944 0 02:14 pts/14 00:00:00 bash
m@meng:~/tmp$ sh
$/home/m/tmp/test.sh
m 30551 30550 0 02:17 PTS/14 00:00:00/bin/sh/home/m/tmp/test.sh
As the result of the second scenario: the parent shell takes over. Interpreter specified when executing script
m@meng:~/tmp$ cat test.sh
\#!/bin/bash
ps-ef | grep $$ | grep-v grep | grep-v ps
m@meng:~/tmp$ Dash test . SH
m 30610 5944 0 02: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 scripts on the command line
If you do not want to write a combination of commands into a file (slightly troublesome), and the combination is not necessary for long-term preservation, but only temporarily, you can use semicolons to put a bunch of commands on one line and then execute:
m@meng:~/tmp$ ls
onlyme test.sh
m@meng:~/tmp$ cd ... LS
blog new program test.sh tmp wine-git public video document music
Examples.desktop Patches scripts timerecords VirtualBox VMs workspaces template picture Download Desktop
The advantage of doing this is that if the first command takes a long time, using a semicolon will not have to wait for it to finish and then enter the second command. You can enter the second command in advance, and then automatically execute the second after the first command is finished.
However, this is not enough "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 parent shell's environment. To achieve this, you need to enclose these commands in parentheses:
m@meng:~/tmp$ (CD ...; LS)
blog new program test.sh tmp wine-git public video document music
Examples.desktop Patches scripts timerecords VirtualBox VMs workspaces template picture Download desktop
m@meng:~/tmp$ ls
onlyme test.sh
That's the way the script works ~
But there is a drawback to this approach: limited length. The length of a single command that the shell can accept is limited, but it is generally sufficient.