可移植外壳编程资源


65

便携式外壳编程有哪些资源?最终的答案是在所有目标平台上进行测试,但这几乎不可行。

POSIX /统一UNIX规范是一个开始,但它会告诉你也不支持每个实现的水平是什么,也没有什么共同的扩展存在。您可以阅读每个实现的文档,但这非常耗时,而且不完全准确。

在我看来,一种理想的格式应该是某种POSIX规范的社区注释版本,其中每个功能都由其在不同实现中的支持级别进行注释。有这样的事吗?还是还有其他有用的资源?

例如,有Sven Mascheck的shell可移植性页面,但这仅涉及语法元素和一些内置插件,并且仅涵盖旧的shell。我正在寻找更全面的资源。


2
注意:请仅在此处引用一个特定实现的一致性文件,以作答。如果您拥有其中之一,那么相应的标记Wiki将是一个好地方。
Gilles

1
有人需要挖掘autoconfMetaconfig(Perl,rn)的修订历史,并将所有的技巧及其解释性注释集中在一个地方。
geekosaur 2011年

@ geekosaur:好建议。我从没看过autoconf的内部原理,在编写自己的脚本时有什么可以用作指导吗?如果是这样,即使不是绝对的问题,这也将是我的问题的一个很好的答案。
Gilles

5
我相信你们俩都可以轻松找到它,但是对于其他关注此线程的人来说,这是autoconf手册中相关页面的链接:gnu.org/software/hello/manual/autoconf/Portable- Shell.html
J. Taylor,

Answers:



6

除了dash和之外posh,还有bournesh(或bsh传家宝伯恩壳牌,可用于检测Bashisms

Heirloom项目还包括“ Heirloom Toolchest”,它是100多个标准Unix实用程序的集合(可以用作比较命令行选项的起点)。


2
请注意,Bourne外壳不是POSIX外壳,使脚本可移植到Bourne外壳意味着将脚本的语法从标准POSIX sh语言降级为该语言和Bourne外壳的语法之间的公分母。除非您想移植到古老的系统(或Solaris 10或更早的版本,并且没有选择使用/ usr / xpg4 / bin中的标准sh)的选择,否则不值得一提。
斯特凡Chazelas

5

此答案类似,请尝试在posh中执行脚本。

另外,不要忘记将POSIXLY_CORRECT环境变量设置为true,因为这会使许多程序(不仅是shell)更加严格地遵守POSIX标准。


4

使用破折号编写脚本可能是一个开始。


3
使用破折号进行测试是避免偶然依赖ksh / bash功能的最低要求,但我的工作还不止于此:了解其他shell的缺陷(例如zsh的陷阱管理不善),尤其是shell实用程序(例如OpenBSD的find静态)尚未实施-exec +)。
吉尔斯(Gilles)

FWIW,OpenBSD的find-exec utility {} +时下。
库桑兰达

2

在某种程度上,您可以尝试checkbashisms使用Debian / Ubuntu的devscripts软件包。

它不是完美的,但是它具有成为现有起点的好处。例如,对于GNU与BSD /其他差异,它看不到带有sed/ 的经典故障find

默认情况下,它是面向Debian + dash的,该-p标志对于您的情况很有用。


2

如今,您通常可以在系统上找到POSIX shell,因此通常意味着您可以使用POSIX语言编写脚本(对符合性错误进行模运算)。

唯一的问题是/bin/sh有时不是POSIX shell。而且,您必须将该#!行硬编码为脚本,以使其表现为出色的可执行文件。您不能只要求用户研究问题,然后以调用您的脚本/path/to/posix/shell myscript

因此,诀窍是在脚本中使用POSIX功能,但要使脚本自动找到POSIX shell。一种方法是这样的:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -x $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
    # or we could avoid bailing here and just fall back on /bin/sh:
    # echo "falling back on /bin/sh: cross your fingers that it works"
    # posix_shell=/bin/sh
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

还有其他方法,例如代码生成。用一个小的脚本来增强脚本,该脚本需要一个不含#的脚本文件!行,并添加一个。

您可能做的最坏的事情就是开始编写整个脚本,使其在1981年的Bourne shell上运行。只有在您必须为实际上没有任何其他shell的系统编写脚本时,才有必要。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.