【问题标题】:Is there a minimally POSIX.2 compliant shell?是否有最低限度符合 POSIX.2 的外壳?
【发布时间】:2012-07-07 18:49:40
【问题描述】:

在以下意义上是否存在至少符合POSIX.2 的shell(我们称之为mpcsh):

如果mpcsh myscript.sh 在我的(兼容的)系统上表现正确,那么xsh myscript.sh 将在任何兼容系统上的任何兼容 POSIX.2 的 shell xsh 上表现相同。 (“相同”到不太相关的事情,例如错误消息的措辞等)

dash 是否符合条件?

如果没有,有什么方法可以验证myscript.sh 的合规性吗?


编辑(9 年后):

接受的答案仍然有效,但请查看 this blog post 和 chackbashisms 命令 (source)。避免 bashism 与编写符合 POSIX.2 的 shell 脚本不同,但它很接近。

【问题讨论】:

  • Debian Almquist shell (dash) 非常接近。
  • 好的,dash 很接近:合规且简约。但它是 minimal,即我可以相信与 dash 一起工作的脚本可以在任何地方工作吗?如果不是,那就是“关闭,但没有cigar”的情况
  • 问题是你会得到一整套最小的实用程序:最小的cat,最小的grep,最小的dd...除非你正在编写一个纯shell脚本,你的可移植性将取决于您在整个环境中使用的功能。
  • 在某种程度上,编写configure 脚本是一种完全不同的野兽,因为您需要解决不合标准的shell 中已知的缺陷(请参阅gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/…)。
  • 生命太短了:我可以花一个小时来解决 crappix99 对 here documents 长度的 666 字节限制,或者只是指出我的 configure 脚本符合 POSIX.2,现在请去寻找一个更好的外壳......

标签: shell posix


【解决方案1】:

POSIX 开发人员花了数年时间(毫不夸张地说)来解决这个问题:“应用程序符合标准意味着什么?”虽然 POSIX 开发人员能够为标准(POSIX.1 和 POSIX.2)的实现定义一致性测试套件,并且可以将“严格符合应用程序”的概念定义为没有使用超出标准强制元素的接口,他们无法定义一个测试机制来确认特定应用程序“严格符合”POSIX.1,或者shell脚本“严格符合”POSIX。 2.

最初的问题就是这样;验证脚本的一致性测试仅使用完全指定的标准元素。唉,该标准充满了放宽行为定义的“狡猾的词”,使得这样的测试对于任何显着有用性的脚本实际上是不可能的。 (即使不考虑 shell 脚本可以生成和执行 shell 脚本的事实,这也是正确的,因此将“严格符合”的问题等同于停止问题。)

(全面披露:从 1988 年到 1999 年,我是 IEEE-CS TCOS 的工作成员和委员会负责人,这是 POSIX 系列标准的创建者。)

【讨论】:

    【解决方案2】:

    提前悲哀的回答

    它不会帮助你(没有你期望的那么可靠)。


    这就是原因。

    虚拟“POSIX shell”无法解决的一个大问题是标准中措辞模棱两可或根本没有解决的问题,因此 shell 可以以不同的方式实现事物,同时仍遵守标准。

    以这两个关于管道的例子为例,第一个是众所周知的:

    示例 1 - 范围

    $ ksh -c 'printf "foo" | read s; echo "[${s}]"'
    [foo]
    
    $ bash -c 'printf "foo" | read s; echo "[${s}]"'
    []
    

    ksh 在当前 shell 中执行管道的最后一个命令,而bash 在子 shell 中执行所有命令——包括最后一个命令。 bash 4 引入了 lastpipe 选项,使其行为类似于 ksh:

    $ bash -c 'shopt -s lastpipe; printf "foo" | read s; echo "[${s}]"'
    [foo]
    

    所有这些都是(有争议的)根据the standard:

    另外,多命令管道的每个命令都处于子shell环境中;但是,作为扩展,管道中的任何或所有命令都可以在当前环境中执行。

    我不能 100% 确定它们对 extension 的含义,但根据文档中的其他示例,这并不意味着 shell 必须提供一种在行为之间切换的方法,而仅仅是如果它愿意,它可以以这种“扩展方式”来实现。其他人对此的理解不同,并争论 ksh 行为不符合标准,我明白为什么。这种措辞不仅不吉利,而且一开始就允许这样做也不是一个好主意。

    实际上,哪种行为是正确的并不重要,因为它们是“两个大壳”,人们会认为,如果您不使用他们的扩展并且只使用所谓的符合 POSIX 的代码,那么它两者都可以,但事实是,如果您依赖上面提到的一种或另一种行为,您的脚本可能会以可怕的方式中断。

    示例 2 - 重定向

    这是我前几天才知道的,看我的回答here:

    foo | bar 2>./qux | quux
    

    常识和POLA 告诉我,当命中下一行代码时,quux 和bar 都应该已完成运行,这意味着文件./qux 已完全填充。正确的?没有。

    POSIX 声明

    如果管道不在后台(参见异步列表),shell 将等待管道中指定的最后一个命令完成,也可能等待所有命令完成。)

    可能 (!) 等待所有命令完成!哇!

    等待:

    shell 在返回值之前等待管道中的所有命令终止。

    但 没有:

    每个命令(可能是最后一个命令除外)都作为单独的进程运行; shell 等待最后一个命令终止。

    因此,如果您在管道之间使用重定向,请确保您知道自己在做什么,因为这会受到不同的处理,并且可能会在极端情况下严重中断,具体取决于您的代码。

    我可以再举一个与管道无关的例子,但我希望这两个就足够了。

    结论

    有一个标准是好的,不断修改它更好,坚持它是伟大的。但是,如果标准由于模棱两可或许可而失败,事情仍然会意外地破坏,实际上使标准的用处无效。

    这在实践中意味着,除了编写“符合 POSIX 标准”的代码之外,您还需要思考并知道您正在做什么以防止某些事情发生。

    话虽如此,一个尚未提及的 shell 是 posh,根据其手册页,它应该是 POSIX 加上比 dash 拥有的扩展更少,(主要是 echo -n 和 local 关键字) :

    BUGS
       Any bugs in posh should be reported via the Debian BTS.
       Legitimate bugs are inconsistencies between manpage and behavior,
       and inconsistencies between behavior and Debian policy
       (currently SUSv3 compliance with the following exceptions:
       echo -n, binary -a and -o to test, local scoping).
    

    YMMV。

    【讨论】:

    • 我假设的最小外壳必然会省略所有含糊不清的功能(没有管道,抱歉!)所以含糊本身并不是这样一个外壳不存在的原因。但是这样的外壳实际上是没有用的,所以我泪流满面地接受你悲伤的回答:-)
    • 我分享你的眼泪,我也希望有这样的事情 :) 可以将破折​​号或豪华去掉到裸 POSIX 并添加选项以在不同/错误的实现之间切换,我想仍然比没有好.我不知道 POSIX 兼容的busybox 的 ash 是怎样的,但如果这是一个选项,我们将免费获得它的其他工具(sed、awk、grep...),并且还可以删除这些工具。也许是时候开始这样一个项目了?
    【解决方案3】:

    如果没有,有什么方法可以验证 myscript.sh 的合规性吗?

    这基本上是一个质量保证的案例。开始:

    • 代码审查
    • 单元测试(是的,我已经完成了)
    • 功能测试
    • 使用尽可能多的不同 shell 程序执行测试套件。 (ash, bash, dash, ksh93, mksh, zsh)

    就个人而言,我的目标是bash 和ksh93 支持的通用扩展集。它们是可用的 shell 语言中最古老、应用最广泛的解释器。

    编辑 最近我偶然发现了rylnd/shpec - 一个用于您的 shell 代码的测试框架。您可以在测试用例中描述代码的功能,并指定如何验证它们。 披露:我帮助它在 bash、ksh 和 dash 上运行。

    【讨论】:

      【解决方案4】:

      目前,POSIX shell 没有单一的角色模型。

      自最初的 Bourne shell 以来,POSIX shell 采用了许多附加功能。

      我所知道的所有实现这些功能的 shell 都具有超出 POSIX shell 功能集的扩展。

      例如,POSIX 允许以下格式的算术表达式:

      var=$(( expression ))
      

      但它不允许等效:

      (( var = expression ))
      

      由bash 和ksh93 支持。

      我知道bash 有一个set -o posix 选项,但这不会禁用任何扩展。

      $ set -o posix
      $ (( a = 1 + 1 ))
      $ echo $a
      2
      

      据我所知,ksh93 尝试开箱即用地符合 POSIX,但仍允许扩展。

      【讨论】:

        【解决方案5】:

        可能与 canonical shell is ash 最接近,由 The NetBSD Foundation, 在其他组织中维护。

        这个shell called dash 的下游变体更为人所知。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-06
          • 2014-11-05
          • 1970-01-01
          • 2011-01-27
          相关资源
          最近更新 更多