The full text turns to good looking, the original address: http://www.linuxsir.org/bbs/showthread.php? T = 99465. Read the original text.
I think many of the main causes of errors when writing scripts or commands are not familiar with Bash command line processing. I have summarized it here for your reference. Double quotes, single quotes, and eval are also involved.
Code:
+ ------------- + Single quotes
| -------------------------> | -------------------------- |
| -----------------------> | 1. Separated into marks | ---- --------------- |
| -------------------> | Double quotation marks |
| + ------------- + |
|
| Read the next command // |
| + ------------------------------------------- + |
| 2. |
| ------ | Test the first mark |
| Other open keywords |
| Non-Keyword |
| + ----------------------------------------- + |
|
| // |
| + ----------------------------- + |
| Extended alias | 3. Check the first mark |
| ------------ | Alias |
| Not an alias |
| + ----------------------------- + |
|
| // |
| + -------------- + |
| 4. Braces extension |
| + -------------- + |
|
| // |
| + -------------- + |
| 5 .~ Symbol extension |
| + -------------- + |
|
| // |
| + -------------- + Double quotation marks |
| 6. Parameter extension | <--------------- |
| + -------------- + |
|
| // |
| + ------------------------------ + |
| 7. Command replacement (nested Command Line Processing) |
| + ------------------------------ + |
|
| // |
| + -------------- + Double quotation marks |
| 8. Arithmetic extension | ---------------- |
| + -------------- + |
|
| // |
| + -------------- + |
| 9. Word Segmentation |
| + -------------- + |
|
| // |
| + -------------- + |
| 10. pathname extension |
| + -------------- + |
|
| // |
| + ---------------------------------------- + |
| 11. Command query: function, built-in command, executable file | <--- | ----- |
| + ---------------------------------------- +
|
| //
| Add the parameter to the next command + ------------- +
| ---------- Eval -------------- | 12. Run the command |
+ ------------- +
Each line read by shell from a standard input or script is called a pipeline line. It contains one or more commands separated by 0 or multiple pipeline characters (|. Process each MPs queue line in 12 steps.
In combination with the illustration above, 12 steps of the command line are provided here.
1. Split command lines into tokens separated by fixed metacharacters.
:
Space, tab, newline,;, (,), <,>, | ,&
The types of tokens include words, keywords, I/O redirections, and semicolons.
2. Check the first mark of each command to see if it is a keyword without quotation marks or backlash.
If it is an open
For example, if and other control structure start strings, function, {or (, the command is actually a composite command. Shell processes the composite command internally to read the next life
And repeat this process. If the keyword is not the starting string of a composite command (such as a keyword in the middle of a control structure such as then), a syntax error signal is given.
3. Check the first keyword of each command based on the alias list.
If a match is found, the alias definition is replaced and the first step is returned. Otherwise, step 1 is entered. This policy allows recursive aliases and keyword aliases. For example, alias procedure = Function
4. Execute braces Extension
For example, a {B, c} is changed to AB AC.
5. If ~ It is located at the beginning of the word and replaced with $ home ~. Use USR's main directory to replace ~ User.
6. Execute parameter (variable) Replacement for any expression starting with $
7. Replace the expression in the form of $ (string) with a command
Here is the nested command line processing.
8. An arithmetic expression calculated in the form of $ (string)
9. Divide the line parameter, command, and arithmetic replacement parts into words again. This time, it uses the characters in $ ifs as separators instead of the metacharacter set in step 1.
10 *,?, [/] Perform Path Extension, also known as wildcard Extension
11. query commands by command priority table (skipping aliases)
12. Run this command after setting I/O redirection and other operations.
References
1. The first 10 steps are skipped in single quotes.
2. Double quotation marks are skipped from step 1 ~ 5. Step 9 ~ 10, that is, only 6 ~ 8 steps.
That is to say, the double quotation marks ignore the pipe characters, aliases ,~ Replace, wildcard extension, and split into words by separators.
Single quotation marks in double quotation marks do not work, but double quotation marks allow parameter replacement, command replacement, and arithmetic expression evaluate. Double quotation marks can be included in double quotation marks by adding the Escape Character "/" and escaping $ ,',/.
Eval
The role of Eval is to execute command line processing again, that is, to process a command line twice.
It takes some effort to make good use of this command. Let me give you two examples.
Example 1:
Use the eval technique to implement the shell control structure.
Code:
[root@home root]# cat myscript1
#!/bin/sh
evalit(){
if [ $cnt = 1 ];then
eval $@
return
else
let cnt=cnt-1
evalit $@
fi
eval $@
}
cnt=$1
echo $cnt | egrep "^[1-9][0-9]*$" >/dev/null
if [ $? -eq 0 ]; then
shift
evalit $@
else
echo 'ERROR!!! Check your input!'
fi
[root@home root]# ./myscript1 3 hostname
home
home
home
[root@home root]# ./myscript1 5 id |cut -f1 -d' '
uid=0(root)
uid=0(root)
uid=0(root)
uid=0(root)
uid=0(root)
Note: Bash has two special variables that save the parameter list.
$ * Stores the string groups separated by the delimiter specified by $ ifs.
$ @, The parameter list is saved as is, that is, "$1" "$2 "...
Here I use function recursion and eval to implement the for structure.
When eval $ @ is executed, it goes through the following steps:
Step 2, split into eval $ @
Step 2: extend $ @ to hostname
Step 2: Find the built-in command eval
Repeat command line processing. In Step 1, locate the hostname command and execute it.
Note: it may be assumed that why Eval is used? Run the command directly at $.
Error! Here is a typical example.
Code:
[Root @ Home root] # A = "id | cut-F1-D ''"
[Root @ Home root] # $
ID: Invalid option -- F
Run 'id -- help' to obtain more information.
[Root @ Home root] # eval $
Uid = 0 (Root)
If the command line is complex (including pipelines or other characters), an error occurs when you directly execute the $ a string. The analysis is as follows.
$ A is processed in step 1 -- parameter extension, that is, Pipeline Analysis is skipped, so "|", "cut", "-F1 ", "-d" is changed to the parameter of the id command. Of course, an error occurs.
However, Eval is used to process the obtained "ID", "|", "cut", "-F1 ", "-d" these strings are processed by the command line again. This time, the pipeline is analyzed correctly.
All in all, you must ensure that your command or script design can be correctly handled through the command line. Skipping any step may cause unexpected errors!
Example 2:
Set ls color display for the System
Code:
eval $(dircolors -b /etc/dircolors)
The eval statement notifies shell to accept eval parameters and run them again through all the steps processed by the command line.
It allows you to write scripts to create command strings at will, and then pass them to shell for execution;
$ () Is the output string of the command to be returned.
The dircolors command generates the bash code for setting the environment variable ls_colors according to the/etc/dircolors configuration file. The content is as follows:
Code:
[Root @ localhost root] # dircolors-B> TMP
[Root @ localhost root] # Cat TMP
Ls_colors = 'no = 00: fi = 00: di = 01; 34: Ln = 01 ;......
Export ls_colors
# The configuration file is not specified here, So dircolors generates code based on the preset database.
Its output is passed to shell by the eval command.
Eval is a flexible application of BASH Shell Command Line Processing rules, and then constructs "intelligent" commands to implement complex functions.
The command mentioned above is a very common application of eval. It repeats the command line parameter passing process and purely executes the command.
In fact, it is a challenge of Bash and a required skill for senior bash programmers.
Command priority table
1. Alias
2. Keywords
3. Functions
4. built-in commands
5. script or executable program ($ PATH)
In view of some puzzles I may encounter during my studies, I will give some interesting commands.
Command builtin enable
As mentioned in the above command line, step 1 will perform command search. What is the specific process of the command line?
Its default search order is function, internal commands, scripts, and executable code. We often need to skip some search items in actual programming to meet certain functional requirements. At this time, we need to use these three commands to use magic ~~
Command
Skip the search for aliases and functions. In other words, it only looks for internal commands and scripts or executable programs found in the search path.
Here is an interesting example.
Code:
[root@home root]# type -all pwd
pwd is a shell builtin
pwd is /bin/pwd
[root@home root]# cat myscript2
#!/bin/sh
pwd(){
echo "This is the current directory."
command pwd
}
pwd
[root@home root]# ./myscript2
This is the current directory.
/root
I replaced the built-in command PWD and external command/bin/pwd with the PWD () function, and then executed the built-in command PWD in the script. Why should we use command here? To avoid recursive loops, because the function name has the same name as the built-in command, and the priority of the function is higher than that of the built-in command.
Builtin
As the name suggests, it only looks for built-in commands. This command is very simple.
Enable
Unlike builtin, It shields a built-in command and allows you to run a shell script or executable code with the same name without providing a full path name.
For example.
The PWD command has two built-in commands: shell and executable.
After some strange path names are executed, the shell's built-in PWD prints an "error message", but the external PWD prints the "original face" of the current directory ". See the following:
Code:
[root@home root]# cd //
[root@home //]# pwd
//
[root@home //]# type -all pwd
pwd is a shell builtin
pwd is /bin/pwd
[root@home //]# /bin/pwd
/
[root@home //]# enable -n pwd
[root@home //]# pwd
/
In this way, after you use enable-N to block the built-in PWD command, you can use the external PWD to print the correct path name.
Bash is profound and profound. I hope you can learn it well.