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

    技术2026-10-03  3

     

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

    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)