Order-Ambiguous Shell I / O重定向的一致性如何?

时间:2017-04-06 04:35:57

标签: bash shell parsing cmd io-redirection

这个引人入胜的帖子:

How is this command legal ? “> file1 < file2 cat”

突出显示了一个看似格式错误的cat调用&#34; shell&#34; (一个Linux shell,大概是BASH)。基本上,shell似乎能够从一系列字符串中的模糊位置获取可执行文件,然后使用I / O重定向到流/文件描述符。

根据我的理解,基本过程是:

  1. 查找重定向模式和read them into or out of appropriate streams / file descriptors(示例:1>(stdout))(这是在命令中启动可执行进程之前发生的!(例如{{ 1}}来电))
  2. 在字符串列表中查找可执行流程。
  3. 启动可执行流程
  4. 暂停进程完成或继续(根据需要)在步骤1中检测到的各种输出。
  5. 这导致了一些令人惊讶的逻辑。例如,在执行cat后的新目录中:

    • echo "dog" > cat:写道&#34; dog&#34;使用shell工具<cat cat >dog

    • 从文件catdog
    • cat:覆盖第一个命令,留下一个空白的<cat cat> cat cat文件(不确定在第二个命令的中间发生了什么)。

    • cat:创建空文件<cat cat> cat cat >dog 2>moredog,用空文件覆盖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):

    1. dog(Linux)
    2. BASH(Linux)
    3. TCSH(Linux)
    4. KSH(Linux)
    5. ZSH(Windows)
    6. ...是这种顺序模糊的I / O重定向解析...

      1. 所有人都支持? (我只有时间测试CMD(Linux)和BASH(Windows)。)
      2. 它是否支持所有受支持的可执行文件或仅支持核心shell实用程序?
      3. 这些shell用于处理流/描述符的清理/排序的规则是什么,特别是在根据子串的选择解析重定向看起来不明确的命令时(例如cmd其中stuff.dat>1test.dat<2test.dat }和1test.dat是文件)
      4. 他们的解析规则在多大程度上在shell之间保持一致?
      5. 是什么决定了这些shell中具有复杂I / O重定向模式的命令的失败?

2 个答案:

答案 0 :(得分:8)

对于POSIX shell--即试图实现Posix标准的shell - 解析算法实际上相当简单,并且还在该标准中进行了记录。其中包括您列表中的bashkshzsh(以及其他内容,例如dash),但不包括Windows cmdtcsh类似但不是Posix。

重定向不是“命令模糊”。它们被解析并从左到右执行。唯一可能奇怪的部分是它们可能与命令及其参数任意交错,但由于每个重定向都在重定向操作符之前,因此不会产生歧义。

对于simple commands,程序大致如下:

  1. 该命令分为单词。重定向运算符之前的单词是重定向;这些将从命令中删除并保存以供以后处理。

    请注意,重定向运算符是自我分隔的,因此a> ba >ba>b之间没有任何区别。所有这些都是单词a,重定向运算符>和单词b>b将被视为重定向。因此语法<a> b可能会让人类读者感到困惑(因此应该避免),但它并不会混淆shell,因为shell将它视为以<a >b更常规的方式编写的

  2. ID=开始的前导词是赋值(其中ID是看起来像变量名的任何内容)。这些也被删除以便以后处理。与重定向不同,这些是唯一被识别的,直到第一个单词(如果有的话),这不是作业。

  3. 根据扩展规则扩展剩余的单词(如果有),这可能涉及拆分扩展单词。扩展后的第一个单词(如果有)是命令,剩下的单词是命令参数。

  4. 从左到右执行重定向。输出重定向(>foo)创建或截断指定文件;追加重定向(>>foo)仅创建文件。

  5. 分配和应用分配。如果有命令,则分配将应用于命令将运行的子shell环境;否则,它们将应用于当前的shell环境。

  6. 如果有命令,则执行命令参数字作为argc/argv参数传递给它。

  7. 例如,似乎让您困惑的行<cat cat> cat cat从左到右解析为:

    • <cat,输入重定向
    • cat,一个命令
    • >cat,输出重定向
    • cat,一个论点

    导致在使用参数<cat调用命令>cat之前执行重定向catcat。如果在执行该行之前当前目录中不存在文件<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,需要获取所需的文件/句柄。如果可以建立所有内容,那么命令将在创建的上下文中执行。

所以,失败可能是

  • 语法问题(解析时)
  • 资源请求问题(在开始执行命令之前创建重定向上下文时)
  • 权利/硬件问题(执行命令期间)