shell命令解析中扩展与重定向顺序问题 .

来源:互联网 发布:中国纺织业出口数据 编辑:程序博客网 时间:2024/06/10 07:59

今天群里有人问了个问题:

echo $((12+34.0))  >/dev/null 2>&1

上句话中的错误怎么没有被重定向呢?

 

执行情况如下:

[root@rac0 ~]# echo $((12+34.0))  >/dev/null 2>&1

echo $((12+34.0))  >/dev/null 2>&1

-bash: 12+34.0: syntax error: invalid arithmetic operator (error token is ".0")

 

 

 

仔细检查了下命令,首先想到的是重定向的顺序问题

这里先对标准输出重定向到null,再把标准出错重定向到null,没错

那为什么出错信息还会再进行输出呢

 

 

考虑了一下,还是要从命令解析的顺序入手

 

这里边涉及到命令解析的二个子过程

1:扩展,具体来说,是$(())形式的命令扩展

2:重定向

 

查看文档(info/man),看这二个子过程的描述:

1:

EXPANSION

       Expansion is performed on the command line after it has been split into words.

说明:扩展是在命令划分单词之后执行的

2:

REDIRECTION

       Before a command is executed, its input and output may be redirected using a special  notation  interpreted  by  the shell

说明:重定向是在命令执行之前的

 

 

再考虑到命令执行的过程,可以简化成如下流程

1:word split,单词分离

2:扩展(包括括号替换,参数替换,命令替换)

3:执行命令

 

把以上二部分结合起来,那就是

1:word split,单词分离

2:扩展(包括括号替换,参数替换,命令替换)

>>>重定向

3:执行命令

 

重定向在扩展之后,在命令执行之前

 

证明:

1:重定向在扩展之后

[root@rac0 a]# filename=2

[root@rac0 a]# echo $filename >$filename

[root@rac0 a]# cat 2

2

[root@rac0 a]#

 

 

2:重定向在命令执行之前

[root@rac0 a]# ls -l

总计 0

[root@rac0 a]# ls -lrt fqef >1

ls: fqef: 没有那个文件或目录

[root@rac0 a]# ls -l

总计 0

-rw-r--r-- 1 root root 0 01-09 23:59 1

 

 

回到上边的问题:

echo $((12+34.0))  >/dev/null 2>&1

上句话中的错误怎么没有被重定向呢?

 

原因就是:

 $((12+34.0)) 这个命令替换的处理,在>/dev/null 2>&1 重定向之前

没重定向前就报错了

 

 

解决方法可以考虑下边二个方法:

1:

(echo $((12+34.0)))  >/dev/null 2>&1

2:

cmd='echo $((12+34.0))'

 

eval $cmd >/dev/null 2>&1

 

加括号的方法,是把命令置入subshell,对subshell进行重定向,在subshell的命令执行之前

 

用eval的方法,是对命令进行二次解析,对命令的重定向,在第一次解析之后,第二次解析之前

 

这样就可以在$((12+34.0)) 之前过行重定向了

0 0