这个引人入胜的帖子:
How is this command legal ? “> file1 < file2 cat”
突出显示了一个看似格式错误的cat
调用&#34; shell&#34; (一个Linux shell,大概是BASH)。基本上,shell似乎能够从一系列字符串中的模糊位置获取可执行文件,然后使用I / O重定向到流/文件描述符。
根据我的理解,基本过程是:
1>
(stdout))(这是在命令中启动可执行进程之前发生的!(例如{{ 1}}来电))这导致了一些令人惊讶的逻辑。例如,在执行cat
后的新目录中:
echo "dog" > cat
:写道&#34; dog&#34;使用shell工具<cat cat >dog
cat
到dog
cat
:覆盖第一个命令,留下一个空白的<cat cat> cat cat
文件(不确定在第二个命令的中间发生了什么)。
cat
:创建空文件<cat cat> cat cat >dog 2>more
和dog
,用空文件覆盖more
个文件。
cat
(创建空文件<cat >dog cat cat <dog >cat
,覆盖dog
w /空文件)
cat
:用空文件覆盖<cat cat >dog 2>much 1>more
;创建文件cat
/ dog
,每个文件包含字符串&#34; dog&#34;,创建空more
(以上列表行为在much
上进行了测试(v4.3.46)。)
现在在某些时候,可怜的外壳决定它已经足够了。例如,面对:
BASH
它抱怨道:
bash:dog:找不到命令
但是有一个额外的惊喜 - 命令实际上已部分完成。与上述大多数示例一样,它使用空白文件覆盖文件<cat dog> cat cat >dog >cat
,并创建了空白文件cat
。
为了更好地理解&#34; most popular Linux shells&#34;中的复杂I / O重定向处理。和CMD(标准Windows shell):
dog
(Linux)BASH
(Linux)TCSH
(Linux)KSH
(Linux)ZSH
(Windows)...是这种顺序模糊的I / O重定向解析...
CMD
(Linux)和BASH
(Windows)。)cmd
其中stuff.dat>1test.dat<2test.dat
}和1test.dat
是文件)答案 0 :(得分:8)
对于POSIX shell--即试图实现Posix标准的shell - 解析算法实际上相当简单,并且还在该标准中进行了记录。其中包括您列表中的bash
,ksh
和zsh
(以及其他内容,例如dash
),但不包括Windows cmd
。 tcsh
类似但不是Posix。
重定向不是“命令模糊”。它们被解析并从左到右执行。唯一可能奇怪的部分是它们可能与命令及其参数任意交错,但由于每个重定向都在重定向操作符之前,因此不会产生歧义。
对于simple commands,程序大致如下:
该命令分为单词。重定向运算符之前的单词是重定向;这些将从命令中删除并保存以供以后处理。
请注意,重定向运算符是自我分隔的,因此a> b
,a >b
和a>b
之间没有任何区别。所有这些都是单词a
,重定向运算符>
和单词b
,>b
将被视为重定向。因此语法<a> b
可能会让人类读者感到困惑(因此应该避免),但它并不会混淆shell,因为shell将它视为以<a >b
更常规的方式编写的
从ID=
开始的前导词是赋值(其中ID
是看起来像变量名的任何内容)。这些也被删除以便以后处理。与重定向不同,这些是唯一被识别的,直到第一个单词(如果有的话),这不是作业。
根据扩展规则扩展剩余的单词(如果有),这可能涉及拆分扩展单词。扩展后的第一个单词(如果有)是命令,剩下的单词是命令参数。
从左到右执行重定向。输出重定向(>foo
)创建或截断指定文件;追加重定向(>>foo
)仅创建文件。
分配和应用分配。如果有命令,则分配将应用于命令将运行的子shell环境;否则,它们将应用于当前的shell环境。
如果有命令,则执行命令参数字作为argc/argv
参数传递给它。
例如,似乎让您困惑的行<cat cat> cat cat
从左到右解析为:
<cat
,输入重定向cat
,一个命令>cat
,输出重定向cat
,一个论点导致在使用参数<cat
调用命令>cat
之前执行重定向cat
和cat
。如果在执行该行之前当前目录中不存在文件<cat
,则第一个重定向(cat
)将失败,因此只有在文件执行时才会执行第二个重定向(>cat
)存在;它会立即截断(清空)文件。除非当前目录在PATH中,否则命令cat
将从文件/bin/cat
执行,该文件是另一个文件。由于参数提供给cat
命令,因此它不会使用其标准输入,因此<cat
重定向除了导致整个命令失败之外没有任何效果,除非文件{{1}已经存在。由于文件cat
将在执行命令cat
之前被截断,因此不会将任何内容写入标准输出,文件cat cat
将保持为空。
关于你的上一个问题:
除了有关错误处理的一些细节之外,这些规则同样适用于所有简单命令,无论是否内置。
cat
中的2
并不特殊,因此>2foo
是文件名。 FD复制用2foo
重定向运算符表示; >&
被视为尝试复制>&2foo
,这是无效的,因为2foo
不是整数。 Posix将此视为未指定的行为,因此实际的shell可能会做得很好。有关详细信息,请参阅Posix shell规范的Section 2.7.5(或至少是官方行)。
由于文件不存在或文件的权限不允许操作,重定向可能会失败。如上所述,重定向从左到右执行,这可能会对“复杂”情况产生影响。
答案 1 :(得分:2)
抱歉,linux不是我的区域,但cmd
是。这是cmd
有限的答案,您必须加入更多信息。
全部支持吗?
基本重定向运算符(<
,>
,>>
,|
)包含在ms-dos 2.0中(仍为command.com
)且已可用从那以后的所有版本。
从Windows 95(仅来自内存),句柄重复运算符(>&
,<&
)也可用。
other shells中存在的更多外来 / 非标准运算符不可用。
它是否支持所有受支持的可执行文件或仅支持核心shell实用程序?
在cmd
中,您可以请求重定向所需的任何可执行文件或内部命令,但结果将取决于可执行文件(在控制台模式下是否与)stdin
/ {{1 }} / stdout
。
实施例。
stderr
,控制台子系统可执行文件不允许输入重定向
timeout.exe
,图形子系统可执行文件允许您使用mshta.exe
获取对FileSystemObject
的引用并写入
使用的规则是什么?
StdOut
解析规则很简单。左到右。如果最终解析的命令有意义(不是不平衡或明显错误),则执行它,否则您会出现语法错误。
cmd
解析命令并确定没有语法错误后,必须在启动命令之前创建重定向。如果没有任何问题(存在输入文件,可以写入输出文件),则相应的句柄将被取消,程序/命令将被启动(如果存在)。
他们的解析规则在多大程度上在shell之间保持一致?
i = stdin input redirection
o = stdout output redirection
e = stderr output redirection
c = command to execute
a = arguments to the command
> file1 < file2 cat
^o ^i ^c
<cat cat >dog
^i ^c ^o
<cat cat> cat cat
^i ^c ^o ^a
<cat cat> cat cat >dog 2>more
^i ^c ^o ^a ^o ^e Second output cancels & replaces first one
<cat >dog cat cat <dog >cat
^i ^o ^c ^a ^i ^o Second i/o set cancels & replaces fist one
<cat cat >dog 2>much 1>more Second output cancels & replaces first one
^i ^c ^o ^e ^o
<cat dog> cat cat >dog >cat Multiple output replacement
^i ^c ^o ^a ^o ^o
stuff.dat>1test.dat<2test.dat
^c ^o ^i
规则在Windows版本之间保持一致,并向后兼容旧版cmd.exe
中使用的语法。
只是一个意见,但是,为什么炮弹之间有任何一致性?如果一切都一致,为什么要有多个?
是什么决定了这些shell中具有复杂I / O重定向模式的命令失败?
你如何确定失败?你如何确定成功? shell将尝试做你所问的,而不是你想要的。甚至清晰的命令也可以以先验unspected的方式运行。
command.com
parses命令并将它们转换为内部表示形式。在该表示中,与请求的命令相关的数据与重定向信息分离。在开始执行任何操作之前,“命令部分”和“重定向部分”都必须在语法上正确(从解析器的角度来看)。
当即将执行命令时,重定向请求为processed,需要获取所需的文件/句柄。如果可以建立所有内容,那么命令将在创建的上下文中执行。
所以,失败可能是