good job!
總算有人看得懂了。
不過,要細說的話,要扯上 shell 在 interpret 一個 command line 時的 priority 。
基本上,其順序如下:
1,將 line 拆成 words (IFS很重要)
2,括展 alias
3,擴展 { }
4,擴展 ~
5,擴展 $variable, $(command), `command`
6,重組再拆成 words
7,括展 wildcards
8,處理 I/O redirection
9,載入命令運行
如果大家有O'Reilly英文版的 Learning the Bash(2nd)的話,請多端詳p178的圖(細節略異)
回到LZ的問題,看上面 5 跟 6 的順序然後才是 9 。
也就是在 6 重組命令時 $A 已經完成替換,當時的 environment 是沒賦值,
因此重組後就是 A=B echo
然後在第 9 的步驟運行命令時, A=B 是給 echo 命令的 local environment,
不管是否 built-in command,都不影響當前的 shell (不同的 shell 在實作上或有差異)
所以第二行的 echo $A 也是得到沒賦值
我通过eval说明赋值是成功的,而不是65楼所说的赋值不成功。
第一步使用 metacharacter,与IFS没有关系
|
The following is a brief description of the shell's operation when it
reads and executes a command. Basically, the shell does the following:
1. Reads its input from a file (*note Shell Scripts::), from a string
supplied as an argument to the `-c' invocation option (*note
Invoking Bash::), or from the user's terminal.
2. Breaks the input into words and operators, obeying the quoting
rules described in *Note Quoting::. These tokens are separated by
`metacharacters'. Alias expansion is performed by this step
(*note Aliases::).
`IFS'
A list of characters that separate fields; used when the shell
splits words as part of expansion.
`metacharacter'
A character that, when unquoted, separates words. A metacharacter
is a `blank' or one of the following characters: `|', `&', `;',
`(', `)', `<', or `>'.
8.05 命令行的评价(evaluation)
下面是C shell 解释命令行的顺序:
1. 历史替换
2. 分裂词(包括特殊字符)
3. 更新历史表
4. 解释单引号(') 和 双引号(")
5. 别名替换
6. 输入和输出的重定向(如 > < 和 |)
7. 变量替换
8. 命令替换
9. 文件名扩展
(Bourne shell 的解释顺序本质上是一样的,除了它不执行历史替换和别名替换之外)
所以
A=B echo $A
的执行过程应该是这样的:
1. 没有历史操作符, 因此不进行历史替换(Bourne shell 不执行这一步)
2. 分裂词,每碰到未加引号的空白字符就会产生一个新“词”。这些词是 A=B、echo、$A。
3. shell 将命令行放到历史列表中。(Bourne shell 不执行这一步)
4. 没有引号需要解释
5. 没有别名需要替换
6. 没有输入或输出重定向需要处理
7. shell注意到变量$A,并把它替换成空
8. shell寻找左单引号,执行左单引号中的任何命令,并且将命令的输出插入到命令行中。在本例中,没有这方面的事需要做。(如果左单引号内有通配符或者变量,那么在shell运行左单引号中的命令之前它们是不会被解释的)
9. shell寻找通配符。本例中没有,不需要处理
10. shell 执行 A=B, 执行 echo 。
8.05 命令行的评价(evaluation)
下面是C shell 解释命令行的顺序:
1. 历史替换
2. 分裂词(包括特殊字符)
3. 更新历史表
4. 解释单引号(') 和 双引号(")
5. 别名替换
6. 输入和输出的重定向(如 > < 和 |)
7. 变量替换
8. 命令替换
9. 文件名扩展
(Bourne shell 的解释顺序本质上是一样的,除了它不执行历史替换和别名替换之外)
所以
A=B echo $A
的执行过程应该是这样的:
1. 没有历史操作符, 因此不进行历史替换(Bourne shell 不执行这一步)
2. 分裂词,每碰到未加引号的空白字符就会产生一个新“词”。这些词是 A=B、echo、$A。
3. shell 将命令行放到历史列表中。(Bourne shell 不执行这一步)
4. 没有引号需要解释
5. 没有别名需要替换
6. 没有输入或输出重定向需要处理
7. shell注意到变量$A,并把它替换成空
8. shell寻找左单引号,执行左单引号中的任何命令,并且将命令的输出插入到命令行中。在本例中,没有这方面的事需要做。(如果左单引号内有通配符或者变量,那么在shell运行左单引号中的命令之前它们是不会被解释的)
9. shell寻找通配符。本例中没有,不需要处理
10. shell 执行 A=B, 执行 echo 。