Shell输入输出重定向的顺序模糊性有多一致?
Shell输入输出重定向的顺序模糊性有多一致?
这篇引人入胜的帖子“这个命令如何合法?“> file1 < file2 cat”展示了一个看似格式错误的cat
命令在“shell”(一个Linux shell,可能是BASH)中的令人惊讶的行为。基本上,shell似乎能够从一系列字符串中的模糊位置获取可执行文件,然后使用I/O重定向到流/文件描述符。
我理解的基本过程是:
- 查找重定向模式并将其读入/输出适当的流/文件描述符中(示例:
1>
(标准输出))(这发生在命令中可执行进程开始之前!(例如cat
命令)) - 在字符串列表中找到可执行进程。
- 启动该可执行进程。
- 根据步骤1中检测到的输出类型暂停等待进程完成或继续进行。
这导致了一些令人惊讶的逻辑。例如,在执行echo "dog" > cat
后,在一个新的目录中:
cat cat >dog
:使用shell工具cat
将文件cat
中的内容写入dog
cat cat> cat cat
:覆盖第一个命令,留下一个空的cat
文件(不确定第二个命令中间会发生什么)。cat cat> cat cat >dog 2>more
:创建空文件dog
和more
,覆盖cat
文件为空文件。cat >dog cat cat
(创建空文件cat dog
,将cat
覆盖为空文件)cat cat >dog 2>much 1>more
:将cat
覆盖为一个空文件;创建包含字符串“dog”的文件dog
/more
,创建空文件much
(以上行为在BASH
(版本4.3.46)上进行了测试。)
现在,在某个时候,这个可怜的shell决定已经受够了。例如,面对以下命令时:
cat dog> cat cat >dog >cat
它抱怨:
bash: dog: command not found
但是这里有一个额外的惊喜--这个命令实际上部分完成了。和上述大多数示例一样,它覆盖了文件cat
为空文件,并创建了一个空文件dog
。
为了更好地理解在“最流行的Linux shell”和CMD(标准Windows shell)中处理复杂的I/O重定向的方式:
BASH
(Linux)TCSH
(Linux)KSH
(Linux)ZSH
(Linux)CMD
(Windows)
...这种模糊的顺序I/O重定向解析...
- 它们都支持吗?(我只有时间测试了
BASH
(Linux)和cmd
(Windows)) - 它们支持所有可执行文件还是只支持核心shell工具?
- 这些shell在处理流/描述符的清理/排序时使用的规则是什么,特别是在解析命令时,重定向似乎基于子字符串的选择是模糊的(例如
stuff.dat>1test.dat<2test.dat
,其中1test.dat
和2test.dat
是文件) - 它们的解析规则在不同shell之间的一致程度是由什么决定的?
- 在这些shell中,什么会导致复杂的I/O重定向模式的命令失败?
“命令的解析算法是相当简单的,并且在Posix标准中有所记录。”这个问题的出现是因为对于POSIX shell来说,重定向操作是有顺序的,不会导致二义性。解决方法是按照从左到右的顺序解析和执行重定向操作。
重定向操作被解析和执行的顺序是从左到右的,每个重定向操作之前都有一个重定向操作符,因此不会产生二义性。对于简单命令,解析过程如下:
1. 命令被拆分成单词。以重定向操作符开头的单词是重定向操作,这些操作会被从命令中移除并保存以供后续处理。
2. 以“ID=”开头的单词是赋值语句(其中ID可以是任何看起来像变量名的内容)。这些赋值语句也会被移除以供后续处理。与重定向操作不同的是,在第一个不是赋值语句的单词之前,只有赋值语句会被识别。
3. 剩下的单词(如果有的话)会根据扩展规则进行扩展,可能会导致扩展后的单词被拆分。扩展后的第一个单词(如果有的话)是命令,剩下的单词是命令的参数。
4. 重定向操作从左到右依次执行。输出重定向(例如“>foo”)会创建或截断指定的文件;追加重定向(例如“>>foo”)只会创建文件。
5. 赋值语句会被扩展并应用。如果有命令存在,赋值语句会应用于命令将要运行的子shell环境;否则,它们会应用于当前的shell环境。
6. 如果存在命令,就会执行该命令,并将命令参数作为“argc/argv”参数传递给它。
例如,对于语句“
- “ - “cat”是一个命令。 - “>cat”是一个输出重定向操作。 - “cat”是一个参数。 这导致在调用命令“cat”并传递参数“cat”之前,重定向操作“ 关于您的最后几个问题: - 这些规则同样适用于所有的简单命令,无论是内置命令还是外部命令,除了一些关于错误处理的细节之外。 - 在“>2foo”中,数字“2”并没有特殊含义,所以“2foo”是一个文件名。重定向操作符“>&”用于复制文件描述符,因此“>&2foo”被视为试图复制“2foo”,但是由于“2foo”不是一个整数,所以这是无效的。Posix将此视为未指定的行为,因此实际的shell可能会做任何事情。有关详细信息,请参阅Posix shell规范的2.7.5节。 - 重定向操作可能会因为文件不存在或文件权限不允许操作而失败。如上所述,重定向操作按照从左到右的顺序执行,这在“复杂”情况下可能会有影响。 对于您对“ 解释如下:当文件被重定向为输出时,它会在打开时被截断。请参阅我的第4点。另外,正如我之前提到的,如果给“cat”命令提供参数,它就不会从标准输入读取。有关更多信息,请参阅“man cat”。我可能误读了“
原因:文章中提到,这是一个针对cmd的有限回答,作者不熟悉linux。作者提到了一些关于cmd中I/O重定向的问题,但是没有给出具体的解决方法。
解决方法:文章中没有明确给出解决方法。
文章整理如下:
I/O重定向是在命令行中常用的功能之一,它可以将命令的输入和输出重定向到文件或其他设备上。然而,不同的命令行环境对于I/O重定向的支持和解析规则可能存在差异。
在cmd(Windows命令提示符)中,基本的重定向操作符(<、>、>>、|)在ms-dos 2.0中就已经被包含,并且在此后的所有版本中都可用。从Windows 95开始,还可以使用复制句柄操作符(>&、<&)。
在cmd中,可以对任何可执行文件或内部命令进行重定向请求,但结果取决于可执行文件是否能够与stdin、stdout或stderr进行交互。例如,timeout.exe是一个控制台子系统可执行文件,不允许输入重定向;而mshta.exe是一个图形子系统可执行文件,可以使用FileSystemObject来获取对StdOut的引用并写入它。
cmd的解析规则很简单,从左到右。如果最终解析的命令是合理的(没有不平衡或明显错误),则执行该命令,否则会出现语法错误。
命令解析后,在启动命令之前必须创建重定向。如果没有任何问题(输入文件存在,输出文件可以写入),则分配适当的句柄并启动程序/命令(如果存在)。
cmd.exe的解析规则在Windows版本之间保持一致,并与旧版本的command.com使用的语法向后兼容。至于不同命令行环境之间是否应该具有一致性,作者并没有给出明确的意见。
对于复杂的I/O重定向模式,命令失败的判断标准是什么?命令尝试执行您请求的操作,而不是您想要的操作。即使是明确的命令,也可能以预先不可预料的方式行为。
失败可能是语法问题(在解析过程中),资源获取问题(在创建重定向上下文之前,开始执行命令时),或者是权限/硬件问题(在执行命令时)。
这篇文章主要讨论了cmd中I/O重定向的一些问题,但没有给出具体的解决方法。文章提到了cmd中的解析规则和一些命令的例子,以及命令失败的可能原因。同时,文章也提到了不同命令行环境之间是否应该具有一致性的问题。