然后检查第一个单词echo是否为关键字,例如if或for,这里不是所以命令不变继续处理。
检查第一个单词依然是echo 是否为别名,这里不是,继续执行。
扫描所有单词是否需要波浪号展开,本例中,~+为ksh93与bash的扩展,等同于$PWD,也就是当前的目录。token 2将被修改变成如下:
echo /tmp/x/${f}[12] $y $(echo cmd subst) $((3 + 2))
下一步变量展开:token2与token3被修改变成:
echo /tmp/x/f[12] a b $(echo cmd subst) $((3 + 2))
再来要处理的是命令替换。注意,这里可递归引用列表里的所有步骤!在次例中,因为我们试图让所有的东西容易理解,因此命令替换修改了token4,结果如下:
echo /tmp/x/f[12] a b cmd subst $((3 + 2))
现在执行算术替换,结果如下:
echo /tmp/x/f[12] a b cmd subst 5
前面所有的展开产生的结果,都将再一次被扫描,看看是否有#IFS字符,如果有则它们是作为分隔符,产生额外的单词。
最后的替换阶段是通配符展开变化如下:
echo /tmp/x/f1 /tmp/x/f2 a b cmd subst 5
这时,shell已经准备好要执行最后的命令了。它会去寻找echo。正好ksh93与bash里的echo都已内建到shell中。
shell实际执行命令。首先执行>out的重定向,再调用内部的echo版本。这一系列完成了这句语句的执行。
eval语句是再告知shell取出eval的参数,并再执行它们一次,是他们经过整个命令行的处理步骤。看一个例子:
listpage="ls | more"
$listpage
运行之后你会发现shell把|与more看作ls的参数,而不是直接产生一页页的文件列表。这是由于在shell执行变量时,管道字符出现在步骤5,也就是在它确实寻找管道字符之后(在步骤1).变量的展开一直要到步骤8才进行解析。结果,shell把 | 与more看作ls的参数,使得ls会试图在当前目录下寻找名为|与more的文件。
现在,想想eval $listpage吧,在shell到达最后一步时,会执行带有ls、|与more参数的eval,这会让shell回到步骤1,具有一行包括了这些参数的命令。在步骤1发现|后,将该行分割为两个命令:ls 和more。每个要被处理的命令都以一般方式执行,最后的结果是在当前目录下分页的文件列表。
还有两个其他的结构,有时也很有用,subShell与代码块。
subShell是一群被括在圆括号里的命令,这些命令会在另外的进程中执行。当你需要让一小组的命令在不同的目录下执行时,这些命令会在另外的进程中执行。如:
tar -cf - . | (cd /newdir; tar -xpf - )
左边tar产生当前目录打包文件,将它传送给标准输出。右边的cd命令会先切换到新目录,也就是让打包文件在此目录下解开。然后,右边的tar将从打包文件里解开文件,请注意,执行此管道的shell并未更改它的目录。
代码块概念上与subShell雷同,只不过它不会建立新进程。代码块用花括号括起。且会对主脚本造成影响(比如当前目录)。一般花括号被视为关键字,即它们只有出现在命令的第一个符号时被识别。实际上,这表示你必须将结束花括号放置在换行符或分号之后。










