今天群里有人问了个问题:
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)) 之前过行重定向了