首页 > 代码库 > 《学习bash》笔记--命令行处理

《学习bash》笔记--命令行处理

shell从标准输入或脚本中读取的每行称为一个管道行,它包含一或多个由0个或多个管道符分割的命令,对其读取的每个管道

行,执行下面的操作。


1.将命令分成由固定元字符集分隔的记号:SPACE、TAB、NEWLINE、;、(、)、<、>、|和&。记号类型
包括单词、关键字、I/O重定向符和分号。
2.检测每个命令的第一个记号,查看为不带引号或反斜线的关键字。如果是一个开放的关键字,如if和
其他控制结构起始字符串、function、{或(,则命令实际上为一复合命令。shell在内部对复合命令进行
处理,读取下一个命令,并重复这一过程。如果关键字不是复合命令的起始字符串(例如,是一个控制
结构中间出现的关键字,如then、else或do等),则shell给出语法错误信号。
3.依据别名列表检查每个命令的第一个关键字。如果找到相应匹配,则替换其别名定义,并退回到第一步;
否则进入第4步,该策略允许递归别名,还允许定义关键字别名。
4.执行大括号扩展,例如,a{b,c}变成ab ac。
5.如果~位于单词的开头,使用用户的主目录替换。
6.对任何以符号$开头的表达式执行参数替换。
7.对形式$(string)的表达式进行命令替换。
8.评估形式为$((string))的算术表达式。
9.把行的参数、命令和算术替换部分再次分成单词。这次它使用$IFS中的字符做分隔符而不是步骤1中的元
字符集。
10.对出现的*、?和[ / ]对执行路径名扩展,也称为通配符扩展。
11.查找其他源码,使用第一个单词作为命令,首先是一个function命令,然后是一个内置命令,然后是
$PATH内目录里的文件。
12.设置完I/O重定向和其他操作后执行该命令。
此步骤列表很直接,但还不是全部内容,有几种修改该过程的方式:使用引用,使用command,builtin或enable,
以及使用高级命令eval。

1.引用

可以将引用看成shell忽略上面12个步骤中某些步骤的一种方式。特别是:
单引号绕过了前10个步骤。
双引号绕过了步骤1到步骤5,步骤9和步骤10.也就是,在双引号内忽略了管道字符、别名、~替换、通配符扩展和
通过分隔符分裂成单词。双引号内的单引号也没有作用。可以在双引号内包含双引号,方式是在前面加上反斜杠。

2.command、builtin和enable

command不查找别名、关键字和函数,只有所有路径中找到内置命令和PATH中的命令被执行。
例如:
cd()
{
	#some process
	command cd
}
这里要避免函数陷入递归循环中。方法是把command放在cd前面,确保内置命令cd被执行,而不是函数被调用。
builtin类似于command,但更加严格。它只查找内置命令。上面的例子也可以使用builtin。
enable用于屏蔽一个内置命令。
使用enable -a显示所有的命令(可用和不可用)
使用enable显示所有可用的内置命令。使用enable command可以使一个命令可用。
使用enable -n可以显示所有被屏蔽的内置命令,使用enable -n command可以屏蔽一个命令。
例如:
[root@yanPC ~]# enable
enable .
enable :
enable [
[省略]
enable cd
[省略]
[root@yanPC ~]# enable -n cd
[root@yanPC ~]# enable -n
enable -n cd
[root@yanPC ~]# enable -a
enable .
enable :
enable [
[省略]
enable -n cd
[省略]
[root@yanPC ~]# cd /dev
-bash: cd: command not found
[root@yanPC ~]# enable cd
[root@yanPC ~]# cd /dev/
[root@yanPC dev]#

3.eval

eval语句通知shell接收eval参数,并再次通过命令行处理的所有步骤运行它们。例如下面的脚本a.sh:
var1="ls | less"$var1
执行结果为:
# ./a.shls: |: No such file or directoryls: less: No such file or directory
原因是:
对照上面命令执行的步骤,首先执行的是第6步:对任何以符号$开头的表达式执行参数替换,然后继续执行下面的步骤,
而命令中的管道符一直都没有机会被解析,最后作为ls的参数进行执行,导致错误。
正确的脚本应该是:
var1="ls | less"eval $var1
原因是:
首先执行的是第6步:对任何以符号$开头的表达式执行参数替换,然后继续执行下面的步骤,最后在运行命令时判断到
是eval,回到第一步继续执行,此时管道符被解析,最终命令成功被执行。