为什么 echo > 1 2 3 创建一个名为 1 的文件,内容为 2 3?

Kah*_*ahn 11 io-redirection echo

$ echo > 1 2 3; ls -latr 1; cat 1
-rw-rw-r-- 1 kahn kahn 4 Jun 23 14:05 1
2 3
Run Code Online (Sandbox Code Playgroud)

这与>重定向的评估有关吗?这样:

echo > 1 2 3
Run Code Online (Sandbox Code Playgroud)

也可以重写为 并且在技术上是:

echo 2 3 > 1
Run Code Online (Sandbox Code Playgroud)

?

是否有任何资源可以更好地理解 IO 重定向的操作顺序及其评估方式?我承认这个例子可能没什么用,甚至不会经常出现,但我想更好地了解这里到底发生了什么。

fra*_*san 21

您可以参考的适当资源是 POSIX shell 语法,它定义了一个简单的命令:

simple_command   : cmd_prefix cmd_word cmd_suffix
                 | cmd_prefix cmd_word
                 | cmd_prefix
                 | cmd_name cmd_suffix
                 | cmd_name
                 ;
Run Code Online (Sandbox Code Playgroud)

这里最相关的部分是 的定义command_suffix:

cmd_suffix       :            io_redirect
                 | cmd_suffix io_redirect
                 |            WORD
                 | cmd_suffix WORD
                 ;
Run Code Online (Sandbox Code Playgroud)

这是递归的,允许重定向和命令参数以任何顺序出现。

此外,POSIX 将重定向的语法定义为

[n]redir-op word

虽然可选数字n和重定向运算符(>在您的情况下为 )之间不允许有空格,但重定向运算符和以下单词之间允许有任意数量的空格。扩展后,word( 1,在您的情况下) 用作流指向(或来自)的文件的名称。

因此,写成同样合法

simple_command   : cmd_prefix cmd_word cmd_suffix
                 | cmd_prefix cmd_word
                 | cmd_prefix
                 | cmd_name cmd_suffix
                 | cmd_name
                 ;
Run Code Online (Sandbox Code Playgroud)

或者

cmd_suffix       :            io_redirect
                 | cmd_suffix io_redirect
                 |            WORD
                 | cmd_suffix WORD
                 ;
Run Code Online (Sandbox Code Playgroud)

甚至

$ echo  > 1  foo  bar
# ^^^^  ^^^^^^^^^^^^^
#  \     \
#   \     cmd_suffix
#    \  ^^^  ^^^  ^^^
#     \  \    \    \
#      \  \    \    WORD
#       \  \    WORD
#        \  io_redirect
#         cmd_name
Run Code Online (Sandbox Code Playgroud)

(当然,重复> 1没有任何意义)。

为了完整起见:cmd_prefix定义中simple_command的 本身是递归定义的:

cmd_prefix       :            io_redirect
                 | cmd_prefix io_redirect
                 |            ASSIGNMENT_WORD
                 | cmd_prefix ASSIGNMENT_WORD
                 ;
Run Code Online (Sandbox Code Playgroud)

这意味着重定向和变量赋值可以以任何顺序出现在命令之前。

然后你可能有,例如,

$ echo foo >1 bar
Run Code Online (Sandbox Code Playgroud)

或者

$ echo > 1 foo > 1 bar > 1
Run Code Online (Sandbox Code Playgroud)

或者

cmd_prefix       :            io_redirect
                 | cmd_prefix io_redirect
                 |            ASSIGNMENT_WORD
                 | cmd_prefix ASSIGNMENT_WORD
                 ;
Run Code Online (Sandbox Code Playgroud)

这些都是同样合法的,但必须记住,重定向和变量赋值以及扩展是从左到右执行的,它们的顺序可能是相关的(例如,如果infile不存在,outfile则不会被截断,cat <infile >outfile而它在cat >outfile <infile)。