11.15常用工具的局限性

你可以在任何机器上找到的小套工具仍然可以包括一些你应该注意的限制。

awk公司

在用户函数调用中,不要在左括号前留下空白。Posix不允许这样做,GNU Awk拒绝这样做:

$gawk的函数die(){print“Aaaarg!”}开始{die()}'呆呆地看着:cmd。行:2:BEGIN{die()}目瞪口呆:cmd。行:2:^分析错误$gawk‘function die(){打印“Aaaaarg!”}开始{die()}'啊啊!

Posix说,如果一个程序只包含开始'操作,以及不包含的实例获取线路,然后程序仅在不读取输入的情况下执行操作。然而,传统的Awk实现(例如Solaris 10awk公司)阅读并放弃在这种情况下输入。可移植脚本可以重定向来自/开发/空来解决这个问题。例如:

awk'BEGIN{print“hello world”}'</dev/null

Posix在“结束'操作,'$NF(美元)'(大概,1美元')如果没有,则保留上次读取记录的值干预'获取线路'发生。然而,一些实现(例如Solaris 10'/usr/bin/awk’, ‘导航器或者达尔文awk公司')重置这些变量。解决方法是使用'之前的中间变量结束'块。例如:

$猫尾.周{tmp=1}美元结束{打印“a”,$1,$NF,“b”,tmp}$echo 1 | awk-f end.awka b 1$echo 1|gawk-f end.awka 1 1 b 1

如果你想让你的程序具有确定性,不要依赖于对于在阵列上:

$每周的猫结束{arr[“foo”]=1arr[“bar”]=1for(i in arr)打印i}$gawk-f表示awk</dev/nullfoo公司酒吧$nawk-f表示awk</dev/null酒吧foo公司

一些Awk实现,例如HP-UX 11.0的本机实现,锚处理不当:

$echo xfoo|$AWK'/foo|^bar/{print}'$echo bar|$AWK'/foo|^bar/{print}'酒吧$echo xfoo|$AWK'/^bar|foo/{print}'xfoo公司$echo bar|$AWK'/^bar|foo/{print}'酒吧

要么不依赖于这种模式(即使用“/^(.*foo|bar)/’,或者使用一个简单的测试来拒绝这样的实现。

打开'ia64-hp-hpux11.23',Awk处理不当打印转换之后%u个:

$awk'开始{printf“%u%d\n”,0,-1}'0 0

AIX版本5.2对Awk程序中正则表达式和文字字符串的长度。

源自Unix版本7的传统Awk实现,例如Solaris公司/箱子/awk,有很多限制符合Posix。现在AC_程序_工作(请参见特殊程序检查)找到一个没有这些问题的Awk,但如果出于某种原因,您不愿意使用AC_程序_工作你可能需要解决他们的问题。有关更多详细说明,请参见awk公司语言历史在里面GNU Awk用户指南.

传统Awk不支持多维数组或用户定义的功能。

传统Awk不支持-v(v)选项。你可以使用而是在课程结束后进行作业,例如。,$AWK'{打印v$1}'v=x然而,不要忘记这样的作业不是评估,直到遇到它们(例如开始动作)。

传统Awk不支持关键字删除.

传统Awk不支持表达式b条:c(c),,^b条,^=b条.

传统Awk不支持预定义CONVFMT公司ENVIRON公司变量。

传统Awk只支持预定义的功能经验,指数,整数,长度,日志,分裂,把格式数据写成串,平方英尺、和子(substr).

传统Awk获取线路与Posix完全不兼容;避开它。

传统Awk有用于(i in a)…但没有其他用途在里面关键字。例如,它缺少如果(i in a)….

在可移植到传统和现代Awk的代码中,可行性研究必须是只包含一个普通字符的字符串,类似地字段分隔符参数分裂.

传统Awk在一个记录中最多有99个字段。自从一些Awk像Tru64这样的实现会分割输入,即使您没有引用对于脚本中的任何字段,若要避免此问题,请设置'可行性研究'以一种不同寻常的性格和用途分裂.

传统Awk在由第页,共页例如,OFMT=“%.300e”;打印0.1;通常情况下转储核心。

Awk的原始版本限制为每个最多99个字节分裂字段,每个99字节子(substr)子字符串和99个字节中非特定字符的每次运行打印格式,但这些我们所知的所有实际主机上的错误都已修复。

HP-UX 11.00和IRIX 6.5 Awk要求输入文件具有行长度最多3070字节。

基名

很久以前,一些主持人缺乏工作经验基名,和需要使用的可移植脚本快递而不是。现在可以安全使用基名例如:

base=`basename--“$file”`

不要依赖任何选项。

复写的副本

命令'cc-c foo。c(c)'传统上生成对象文件命名食品。。大多数编译器都允许-c(c)待合并具有-o个指定不同的对象文件名,但Posix不需要这种组合和一些编译器缺少支持。请参阅C编译器特性,关于GNU如何制作使用测试此功能AC_PROG_CC_O公司.

当编译如“抄送-o foo foo。c(c)'失败,某些编译器(如Reliant Unix上的CDS)留下一个食品。.

HP-UX系列复写的副本不接受.S系列要预处理的文件和组装。”cc-c foo。S公司“似乎成功了,但事实上成功了没有什么。

默认可执行文件,由“抄送foo。c(c)',可以是

  • a.输出–常见的Posix约定。
  • b.输出–i960编译器(包括海湾合作委员会).
  • a.exe文件–DJGPP端口海湾合作委员会.
  • 输出.exe(_O)–GNV(全球价值)复写的副本OpenVMS上DEC C的包装器。
  • foo.exe文件–各种MS-DOS编译器。

C编译器的传统名称是复写的副本,但其他名称如海湾合作委员会都很常见。Posix 1003.1-2001至1003.1-2017指定名称c99码,但指定了较旧的Posix版本c89码,未来的POSIX标准可能会规定其他命令,无论如何,这些标准名称很少用于实践。通常,C编译器是从使用美元(CC)',因此'的值立方厘米'make变量选择编译器名称。

文件名
大杂烩

将文件组更改为所有者所在的组是不可移植的不属于。

chmod公司

避免使用“chmod-w文件’; 使用'chmod a-w文件'相反,有两个原因。首先,简单-w个不一定使文件不可写入,因为它不影响对应于文件模式创建掩码中的位。第二,Posix说-w个可能被解释为实施特定选项,而不是作为一种模式;Posix建议使用'chmod---w文件“为了避免混淆,但不幸的是--“在某些较旧的主机上不起作用。

化学机械抛光

化学机械抛光对两个文件执行原始数据比较,而差异比较两个文本文件。因此,如果您可以比较DOS文件,即使只检查两个文件是否不同,也可以使用差异以避免由于换行编码。

内容提供商

避免-第页选项,因为Posix 1003.1-2004将其标记为过时及其在特殊文件上的行为是由实现定义的。使用-R(右)而不是。在GNU主机上有两个选项是等效的,但在Solaris主机上(例如)cp-r从管道中读取而不是复制它们。AIX 5.3复制目录可以使用某些目录层次结构损坏其自身的内存并出错或卸载堆芯:

mkdir-第12345678/12345678页/第12345778/1234567页
触摸12345678/12345678/x
cp-R 12345678吨cp:0653-440 12345678/12345678/:名称过长。

一些内容提供商实现(例如,BSD/OS 4.2)不允许不存在的目标目录末尾的斜杠。收件人要避免这个问题,请省略尾部斜杠。例如,使用cp-R源/tmp/newdir“而不是”cp-R源/临时目录/新目录/'如果/临时目录/新目录不存在。

这个-(f)现在这个选项是便携式的。

传统上,文件时间戳的分辨率为1秒内容提供商-第页'准确复制了时间戳。然而,许多现代文件系统具有1纳秒分辨率的时间戳。不幸的是,一些老年人cp-p'实现在复制文件时截断时间戳,这可能导致目标文件看起来比来源。截断的准确数量取决于系统调用内容提供商使用。传统上这是美国,分辨率为1秒。不太古老内容提供商GNU Core Utilities 5.0.91(2003)等实现使用实用程序,分辨率为1微秒。现代GNU核心实用程序6.12(2008)等实现可以将时间戳设置为使用现代系统调用的全纳秒分辨率福特门斯乌蒂门萨特当它们可用时。截止日期然而,2011年,许多平台尚未完全支持这些新系统电话。

鲍勃·普鲁克斯指出:“cp-p'总是尝试复制所有权。但无论它是否真的复制所有权由内核实现的与系统相关的策略决策。如果内核允许它发生。如果内核不允许,那么这不会发生。这不是什么内容提供商自身拥有控制权超过。

在Unix System V中,任何用户都可以向任何其他用户加载文件V还有一个非粘滞/临时管理计划。这可能源于在没有恶意用户的商业环境中继承System V。BSD对此进行了更改成为一个更安全的模型,只有root才能大杂烩文件和黏糊糊的/临时管理计划使用。毫无疑问,这源于传统校园环境中的BSD。

GNU/Linux和Solaris默认遵循BSD,但可以配置为允许System V样式大杂烩。在另一方面,HP-UX遵循System V,但可以配置为使用现代安全模型并且不允许大杂烩。由于它是管理员可配置的参数您不能使用内核的名称作为行为的指示器。

日期

的某些版本日期不识别特殊'%'指令,不幸的是,他们没有抱怨,只是把它们传递出去,并成功退出:

$找到对应内核版本OSF1 medusa.sis.pasteur.fr V5.1 732α$日期“+%s”%秒
差异

选项-u个不可携带。

与相比,某些实现(如Tru64)会失败/开发/空。请改用空文件。

目录名

很久以前,一些主持人缺乏工作经验目录名和便携式使用所需的脚本AS_名字(请参见M4sh编程).现在目录名足够,以下内容等效:

dir=`dirname--“$file”`dir=`AS_DIRNAME([“$file”])`
白鹭

尽管Posix不再要求白鹭2001年,一些传统主机(特别是Solaris 10)不支持Posix更换希腊语-E。此外,一些传统实现也会不适用于长输入行。要解决这些问题,请调用AC_PROG_EGREP公司然后使用美元EGREP.

可移植扩展正则表达式应使用“\“只是为了逃跑字符串中的字符'$()*+。?[\^{|”。例如,'\}'不可移植,即使它通常与“}”。

空的备选方案是不可移植的。使用“'相反。对于Digital Unix v5.0实例:

>printf“foo\n|foo\n”|$EGREP'^(|foo|bar)$'|foo公司>printf“bar\nbar|\n”|$EGREP'^(foo|bar|)$'巴|>printf“foo\nfoo|\n|bar\nbar\n”|$EGREP'^(foo||bar)$'foo公司|巴

有关可移植扩展正则表达式中可以显示的内容的更多信息表达式,请参见有问题的表达在里面GNU希腊.

美元EGREP也受到以下方面的限制格雷普(请参见常用工具的局限性).

快递

并非所有实现都遵循Posix规则--'分隔开参数选项;同样,并非所有实现都提供Posix的扩展,第一个参数可以作为有效表达式,而不是以开头的无效选项-’. 执行算术时,请使用“expr 0+$var'如果$变量“可能是一个负数快递将其解释为一种选择。

快递关键字以'开头X(X)',所以使用'快递X英寸单词“:'X正则表达式''保持经验曲解单词.

不要使用长度,子(substr),比赛指数.

快递(‘|’)

您可以使用“|’. 虽然Posix确实要求“快递'''返回空字符串,当您|'将空字符串(或零)与空字符串放在一起。对于例子:

表达式“”

Posix 1003.2-1992返回空字符串对于这种情况,但传统Unix返回“0'(Solaris是例如)。在Posix 1003.1-2001中,规范是更改以匹配传统Unix的行为(即奇怪,但现在解决这个问题已经太晚了)。请注意,同样当空字符串由计算结果产生时,确实会出现问题,如:

expr-bar:foo\|foo:bar

通过避免空字符串来避免这种可移植性问题。

快递(‘:’)

便携式快递正则表达式应使用'\'至仅转义字符串中的字符'$()*.123456789[\^{}”。例如,交替\|',很常见,但Posix没有需要它的支持,所以在可移植脚本中应该避免使用它。类似地,'\+'和'\?“应该避免。

便携式快递正则表达式不应以开头^’. 图案会自动锚定,以便前导^'是无论如何都不需要。

另一方面,“$'锚不可移植在多行字符串上。Posix不明确锚是否适用于每一行,就像在旧版本的GNU核心实用程序中所做的那样,或它是否仅适用于整个字符串的末尾,如Coreutils 6.0和大多数其他实现。

$baz='oo>巴'$expr“X$baz”:“X\(foo\)$”$expr-5.97“X$baz”:“X\(foo\)$”foo公司

Posix标准对于是否expr“a”:“\(b\)”“输出”0'或空字符串。实际上,它在大多数平台上输出空字符串,但可移植脚本不应该假设这一点。例如,QNX 4.25本机快递返回'0”。

人们可能会认为,获得统一行为的一种方法是使用空字符串作为默认值:

表达式a:“\(b\)“\ |”

不幸的是,这与原始表达式完全相同;请参阅快递(‘|')条目以获取更多信息。

一些古老的经验实施(例如。,Solaris 10/usr/ucb/expr)有一个愚蠢的长度限制,导致快递如果匹配的子字符串长于120,则失败字节。在这种情况下,您可能想回到“回波| sed'如果快递失败。如今,这只对罕见的安装程序错误地将/用户界面(usr/ucb)之前/usr/bin(用户/二进制)在里面路径在Solaris 10上。

在Mac OS X 10.4上,快递错误处理模式'[^-]中的'一些情况。例如,命令

expr Xpowerpc-apple-darwin8.1.0:“X[^-]*-[^-]*-\(.*\)”

输出'应用达尔文8.1.0'而不是正确的'达尔文8.1.0”。这种特殊情况可以通过替换“[^--]'对于'[^-]”。

别离开,还有一些!

QNX 4.25快递,除了首选0'至空字符串在退出状态下有一个有趣的行为:它总是1当使用括号时!

$val=“expr”a“:”a“”;echo“$?:$val”0:1$val=`expr'a':'b'';echo“$?:$val”1:0$val=`expr'a':'\(a\)'`;echo“?:$val”1:a段$val=`expr'a':'\(b\)'`;echo“?:$val”1: 0

实际上,如果您准备好捕捉失败,这可能是一个大问题属于快递使用其他方法(例如使用塞德),因为你可能会得到两倍的结果。例如

$expr“a”:“\(a\)”|echo“a”|sed“s/^\(a~)$/\1/”

输出''在大多数主机上,但'aa公司QNX 4.25上的。A类简单的解决方法包括测试快递并使用变量设置为快递或至根据结果。

Tru64系列快递错误地将结果视为数字,如果可以这样解释:

$表达式00001:“.*\(…\)”1

在HP-UX 11上,快递仅支持单个子表达式。

$expr“Xfoo”:“X\(f\(oo\)*\)$”expr:使用了多个“\(”。
fgrep公司

尽管Posix不再要求fgrep公司2001年,一些传统主机(特别是Solaris 10)不支持Posix更换格雷普-F。此外,一些传统实现也会不适用于长输入行。要解决这些问题,请调用AC_PROG_FGREP公司然后使用FGREP美元.

Tru64/OSF 5.1型fgrep公司与空模式不匹配。

找到

GNU的许多操作数找到Posix和在许多平台上都不存在。这些不可移植的操作数包括-跟随,-最大深度,-心智,-打印、和,。请参阅Posix规范找到对于找到操作数现在应该是便携式的。

替换“{}'只有在参数为确切地{},如果它只是一个论点的一部分,就不会。对于实例,在HP-UX 11上:

$触摸foo$找到-名称foo-exec-echo“{}-{}”\;{}-{}

当GNU找到报告'./foo-/foo公司”。Posix允许这两种行为。

格雷普

可移植脚本可以依赖格雷普选项-c(c),-我,-n个、和-v(v),但应避免其他选项。例如,不要使用-w个,因为Posix不需要它和Irix 6.516米格雷普不支持。此外,可移植脚本不应组合-c(c)具有-我,因为Posix不允许这样做。

Posix所需的一些选项实际上是不可移植的。不使用'希腊语-q'抑制输出,因为传统格雷普实现(例如Solaris 10)不支持-q个.不使用'grep-s'以抑制输出,因为Posix-秒不抑制输出,只显示一些错误消息;此外-秒传统的选择格雷普表现良好的喜欢-q个在大多数现代实现中都是这样的。相反,重定向标准输出和标准错误(如果文件不存在),共格雷普/开发/空.检查出口的状态格雷普以确定是否找到匹配项。

QNX4实施无法计算行数grep-c“$”,但与合作grep-c“^”.其他计数方法要使用的行sed-n'$='wc-l型.

一些传统的格雷普实现工作时间不长输入行。在AIX上,默认值为格雷普静默截断长匹配之前输入上的行。

此外,传统实现不支持多个regexp具有-e(电子):他们要么拒绝-e(电子)完全(例如,Solaris 10)或者只遵循最后一个模式(例如IRIX 6.5和NeXT)。收件人解决这些问题,调用AC_PROG_GREP公司然后使用$GREP美元.

另一种可能的多重解决方案-e(电子)问题是用换行符分隔模式,例如:

格雷普·富奥条'英寸.txt

但这与传统的格雷普实现和使用OpenBSD 3.8格雷普.

传统格雷普实现(例如Solaris 10)不支持-E类-F类选项。解决这些问题问题,调用AC_PROG_EGREP公司然后使用美元EGREP、和类似于AC_PROG_FGREP公司FGREP美元.即使你是愿意为Posix寻求支持格雷普,您的脚本应该不同时使用-E类-F类,因为Posix不允许这种组合。

便携式格雷普正则表达式应使用'\'仅限于字符串中的转义字符'$()*.123456789[\^{}’. 例如,交替,'\|',是常见的,但Posix不需要支持基本正则表达式,因此在可移植脚本。Solaris和HP-UX格雷普不支持它。同样,还应避免以下转义序列:\<’, ‘\>’, ‘\+’, ‘\?’, ‘\`’, ‘\'’,\B类’, ‘\b条’, ‘\S公司’, ‘\秒’, ‘\W公司'、和'\w个”。有关可移植正则表达式中可能出现的内容的详细信息,看见有问题的表达在里面GNU希腊.

Posix未指定格雷普在二进制文件上。一个重要的例子是使用BSD格雷普搜索包含嵌入式ANSI转义序列的文本彩色输出到端子('\033[米'是要还原的序列正常输出);行为取决于输入是否可查找:

$printf'esc\033[mape\n'>示例$格雷普。样品二进制文件样本匹配$cat样本|grep。逃跑
参加

在NetBSD上,join-a 1文件1文件2错误地表现为join-a 1-a 21文件1文件2,导致使用警告;解决方法是使用join-a1文件1文件2而不是。

在使用BusyBox工具的平台上参加命令是完全不见了。作为一种解决方法,您可以模拟参加命令使用awk公司脚本。例如,看见https://lists.gnu.org/r/bug-gnulib/2021-04/msg00054.html.

这个-(f)现在的选择是便携的。

符号链接在某些系统上不可用;使用'$(LN_S)'作为便携式替代品。

对于2.04之前的DJGPP版本,模拟符号链接通过生成一个存根来执行可执行文件,该存根反过来调用实程序。此功能也适用于不存在的文件,如Posix规范So’ln-s文件链接'生成链接程序,试图呼叫文件.exe如果运行。但仅此功能适用于可执行文件,所以'cp-p'用于这些系统。DJGPP 2.04版及更高版本完全支持用于符号链接。

最小二乘法

便携式选项包括-阿迪尔图。目前的做法是-我输出所有者和组,即使是古代版本属于最小二乘法省略了组。

在古代东道主身上ls-foo公司'发送诊断'未找到foo'到标准输出,如果foo公司不存在。因此有一个shell命令就像'sources=`ls*.c 2>/dev/null`“并不总是有效,因为等于“源=“找不到*.c”'在没有.c类'文件。这不再是一个实际问题,因为目前最小二乘法实现将诊断发送到标准错误。

的行为最小二乘法在正在并发的目录上修改并不总是可以预测的,因为缓存的位置存在数据竞争返回的信息读目录与当前不匹配目录状态。事实上,MacOS 10.5有一个间歇性错误读目录,因此最小二乘法,有时列出的文件超过如果立即从目录中添加或删除其他文件,则执行一次最小二乘法呼叫。最小二乘法已经对其进行排序输出时,可以通过管道传输结果来避免重复条目通过uniq公司.

mkdir公司

-米-第页选项,如'mkdir-mgo-w-p型目录',经常导致麻烦。自由BSDmkdir公司错误地尝试更改的权限目录即使它已经存在。HP-UX 11.23和IRIX 6.5版mkdir公司通常将错误的权限分配给任何新出生的父母目录.

Posix没有明确说明“mkdir-p foo'应该在以下情况下成功foo公司是一个已经存在的符号链接目录。GNUmkdir公司成功,但Solaris 10mkdir公司失败。

传统mkdir-p实现受到竞争条件的影响。例如,如果您调用mkdir-p账户mkdir-p账户同时,这两个进程都可能检测到缺失,一个人可能会创造,则另一方可能会尝试创建并以失败告终文件已存在诊断。Solaris 10mkdir公司易受攻击,而其他传统Unix系统可能也很脆弱。这种可能的竞争是有害的在多个Make规则调用时生成mkdir-p构造目录。您可以使用安装-sh-d作为安全替换,例如通过设置MKDIR_P=“/path/to/install-sh-d”'在环境中配置,假设包分发安装-sh.

mkfifo公司
建立特别文件

GNU编码标准规定建立特别文件可以安全使用经测试存在的平台;但它通常是便携式的仅用于创建命名的FIFO,因为设备编号是特定于平台。自动测试使用mkfifo公司实现并行测试套件。Posix声明在打开命名FIFO,用于读取和写入;至少Cygwin,这个导致读取或写入该文件的任何尝试都失败描述符。

建立临时文件

Shell脚本可以安全地使用临时文件建立临时文件,但是它并不存在于所有系统中。一种创建保险箱的便携方式临时文件名用于创建模式为700的临时目录使用此目录中的文件。这两种方法都可以防止攻击者尽管如此,还是获得了控制权建立临时文件不太可能失败无缘无故地受到攻击。

下面是创建新临时目录的示例代码$目录'安全:

#在$TMPDIR中创建临时目录$dir(默认/tmp)。#如果可能,请使用mktemp;否则返回mkdir,#使用$RANDOM减少冲突的可能性。:“${TMPDIR:=/tmp}”{目录=`(umask 077&&mktemp-d“$TMPDIR/fooXXXXXX”)2>/dev/null` &&测试-d“$dir”} || {dir=$TMPDIR/foo$$-$RANDOM(umask 077&&mkdir“$dir”)}|退出$?
毫伏

唯一的便携式选项是-(f)-我.

在文件系统之间移动单个文件是可移植的(在Unix中版本6),但它并不总是原子的:当做'mv新现有',有一个关键部分,其中既没有旧版本也没有新版本现有的实际上存在。

在某些系统上,将文件从/临时管理计划有时会导致不需要的(但完全有效的)警告,即使您创建了这些文件夹。这是因为/临时属于一个普通的群体用户不是的成员,并且在中创建的文件/临时管理计划继承的组/临时管理计划。复制文件时,毫伏问题无故障诊断:

$触摸/tmp/foo$mv/tmp/foo。错误→mv:/foo:设置所有者/组(was:100/0):不允许操作$echo$?0$ls-foo公司foo公司

不幸的是,这种恼人的行为符合Posix。

跨装入点移动目录是不可移植的,请使用内容提供商rm(毫米).

DOS变体无法重命名或删除打开的文件支持类似“mv foo栏>foo',尽管这是在Posix主机之间完全可移植。

在10.4.3之前的MacOS X版本中,不支持标准Posix选项-A类,-j个,-N个,或-t吨,或XSI选项,-秒.唯一的支持的Posix选项是-v(v),并且仅支持XSI选项位于-bcdox公司.BSD六边形突起可以改用程序。

在从Solaris 11派生的某些操作系统的某些版本中,打印用零填充的十进制字节值,而不是带空格:

$打印“#!”|od-A n-t d1-n 2035 033

而不是

$打印f'#!'|od-A n-t d1-n 235 33

我们在OpenIndiana和OmniOS上都观察到了这一点;Illumos也可能受到影响。作为一种变通方法,您可以使用八进制输出(选项-到1).

rm(毫米)

这个-(f)-第页选项是可移植的。

调用它是不可移植的rm(毫米)没有选项或操作数。另一方面,Posix现在需要强制删除到默默地当没有操作数时成功(对于像rm-rf$文件列表没有首先检查“$文件列表'为空)。但这并不总是便携式的;至少NetBSDrm(毫米)2008年之前建造的飞机如果诊断失败。

即使父目录可写,也可能无法删除文件并且可以搜索。许多Posix主机无法删除装载点流、工作目录或指向正在执行。

DOS变体无法重命名或删除打开的文件支持类似“rm-foo>foo',尽管这是在Posix主机之间完全可移植。

rmdir(远程管理目录)

正如rm(毫米),一些平台拒绝移除工作目录。

塞德

模式不应包括分隔符(除非转义),即使是作为一部分字符类的。根据Posix,Cray塞德拒绝's/[^/]*$//':使用's%[^/]*$%%”。即使在转义时,模式也不应包括分隔符用作塞德元字符。例如,GNU sed 4.0.9拒绝s、 x\{1\,\},,',而sed 4.1去掉逗号前的反斜杠在计算基本正则表达式之前。

避免括号内出现空模式(即“\(\)’). Posix做了不需要支持空模式和Unicos 9塞德不合格品他们。

联通9塞德在模式上无休止地循环.*\n*”。

Sed脚本不应使用长度超过7个字符的分支标签,并且不应包含评论;AIX 5.3塞德拒绝缩进注释。HP-UX sed最多有99个命令(不包括“:'命令)和48个标签,无法通过使用多个脚本来规避文件。它可以用“第页'每个循环的命令。Solaris公司/usr/ucb/sed拒绝超过限制的用法大约6000字节用于命令的内部表示。

避免冗余;',作为一些塞德实现,例如NetBSD 1.4.2,错误地尝试解释第二个;'作为命令:

$echo a | sed的/x/x/;;s/x/x/'sed:1:“s/x/x/;;s/x/x/”:无效的命令代码;

一些塞德实现的缓冲区限制为4000字节,这限制了输入线、输出线和内部线的大小可移植处理的缓冲区。同样地,不是全部塞德实现可以处理嵌入式NUL(无)缺少尾部换行符。

记住,正则表达式的方括号表达式中的范围仅在“C'(或'POSIX公司')区域设置。同时,支持“[[:上部:]]'不是但是通用的,所以如果你不能保证设置LC_全部,最好拼写出一个范围'[ABCDEFGHIJKLMNOPQRSTUVWXYZ]'而不是依赖“【A-Z】”。

此外,Posix声明正则表达式只是在字符上定义良好。不幸的是,存在这样的平台如MacOS X 10.5,其中并非所有8位字节值都是有效字符,即使该平台有一个单字节C'区域设置。和Posix允许存在多字节C'locale,尽管如此似乎还不是常见的实现。无论如何,这意味着不是所有的字节都会被正则表达式匹配'.’:

$printf'\200\n'|LC_ALL=C sed-n//p|wc-l0$printf'\200\n'|LC_ALL=en_US.ISO8859-1 sed-n//p|wc-l1

便携式塞德正则表达式应使用'\“只是为了逃跑字符串中的字符'$()*.123456789[^n{}’. 例如,交替,'\|',是常见的,但Posix不需要支持,因此应在可移植脚本中避免使用。Solaris公司塞德不支持交替;例如,'sed'/a\|b/d''仅删除包含文字字符串的行'a | b公司”。同样,'\+'和'\?“应该避免。

锚('^'和'$')组内不可移动。

模式中的嵌套括号(例如“\(\(a*\)b*)\)')是可移植到当前主机,但不受一些古代主机的支持塞德SVR3等实现。

一些塞德实施,例如Solaris,限制了星号的作用*'到单字符正则表达式和回指和区间表达式的特殊作用\{\}’, ‘\{,\}',或'\{,n个\}'到单字符正则表达式。这可能会导致意外行为:

$echo“1*23*4”|/usr/bin/sed“s/\(.\)*/x/g”x2x4像素$echo“1*23*4”|/usr/xpg4/bin/sed“s/\(.\)*/x/g”x个

这个-e(电子)选项主要是便携式的。然而,它的论点不能以“”开头’, ‘c(c)',或'',因为这与Tru64 5.1错误相冲突。此外,它的参数不能为空,因为这在AIX5.3上会失败。有些人更喜欢使用“-e(电子)’:

sed-e’命令-1' \-e’命令-2'

与等价物相反:

塞德'命令-1
  命令-2'

以下用法有时是等效的:

塞德'命令-1;命令-2'

但Posix表示,如果命令-1的动词是{’, ‘’, ‘b条’, ‘c(c)’,’, ‘第页’, ‘t吨’, ‘w个’, ‘:',或'#',所以你应该只对不使用分号的简单脚本使用分号动词。

2008年修订版之前的Posix需要-e(电子)选项设置为语法完整的脚本。GNU(全球导航单元)塞德允许传递多个脚本片段,每个片段作为单独的-e(电子)选项,然后将其与片段,未来的Posix版本也可能允许这样做。这个这种方法对于以反斜杠结尾的脚本片段是不可移植的;对于示例塞德Solaris 10、HP-UX 11和AIX上的程序在这种情况下不允许拆分:

$echo a | sed-n-e’i\
“0”0$echo a | sed-n-e“i”-e 0无法识别的命令:0

然而,实际上,这种连接碎片的技术通过-e(电子)适用于多个塞德中的函数{'和'}',即使Posix没有指定:

$echo a | sed-n-e'/a/{'-e s/a/b/-e p-e'}'b条

{}括号内的命令受到进一步限制。Posix 2008表示它们前面不能有地址,'',或';',还有那个每个命令后面必须紧跟一个换行符,不能有任何换行符中间的空格或分号。闭合支架必须单独打开一行,而不是它前面或后面的空白。但是Posix的未来版本可能会标准化括号内地址的使用。

与另一个城市传说相反,你可以随身使用“&中的'的替换部件命令表示“过去是什么”匹配”。Unix版本7的所有后代塞德(至少;我们没有与老年人打交道的第一手经验塞德实现)具有支持它。

Posix要求在'和以下命令。中间可以有空格地址和'’. 例如,在Solaris上:

$echo“foo”|sed-n'/bar/!p’error→无法识别的命令:/bar/!第页$echo“foo”|sed-n'/bar/!p’错误→无法识别的命令:/bar/!第页$echo“foo”|sed-n'/bar/!p’foo公司

Posix还说你不应该合并'和';’. 如果您使用'',最好将其放在由分隔的命令上换行而不是';”。

还要注意,Posix要求“b条’, ‘t吨’, ‘第页',和w个'命令在其参数前紧跟一个空格。另一方面,“:'和后续标签名称。

如果在命令行上指定了sed脚本并以’, ‘c(c)',或''命令,插入文本的最后一行后面应该跟一个换行符。否则一些塞德实现(例如,OpenBSD 3.9)不在插入的文本。

许多塞德实现(例如,MacOS X 10.4,OpenBSD 3.9,Solaris 10/usr/ucb/sed)从文本中去掉前导空格’, ‘c(c)'、和''命令。在前面加上反斜杠解决与Posix的不兼容问题:

$echo flushleft\>缩进的>'刷左的缩进的$echo foo | sed’a\>\缩进的>'刷左的缩进的

Posix要求对于空的正则表达式,最后一个非空的来自地址规范或替换的正则表达式命令。然而,busybox 1.6.1在使用替换命令,其中包含对的后引用空正则表达式;解决方法是重复常规表达式。

$echo abc | busybox sed'/a\(b\)c/s///\1/'sed:没有以前的regexp。$echo abc | busybox sed'/a\(b\)c/s/a\(b\)c/\1/'b条

可移植脚本应注意以下方面的不一致性和选项处理单词边界,因为POSIX没有指定这些边界。

\<\b[[:<:]]Solaris 10是否Solaris XPG4是/否错误NetBSD 5.1否否是FreeBSD 9.1否是GNU是是错误busybox是是错误
塞德(‘t吨’)

一些旧系统具有塞德“忘记”重置t吨'标志。例如在MIPS上RISC/OS和IRIX 5.3上,如果您运行以下命令塞德脚本(行号不是文本的实际部分):

s/keep-me/keepd/g#at端#bs/.*/删除/g#c:结束#d

删除我#1删除我#2留我#3删除我#4

你会得到

删除删除我保持删除

而不是

删除删除保持删除

为什么?当处理第1行时,(c)匹配,因此设置t吨'标志,并生成输出。处理时第2行,“t吨'标记仍然设置(这是错误)。命令(a)不匹配,但塞德不应该清除“t吨'标记替换失败。命令(b)看到标志已设置,因此它清除了它,并跳到(d),因此得到'删除我'而不是'删除’. 处理行(3)时,'t吨“很清楚,(a) 匹配,所以设置了标志,因此(b)清除标志并跳转。最后,由于标志是清晰的,所以第4行被正确处理。

有两件事我们应该记住“t吨中的'塞德.首先,永远记住“t吨'跳转,如果一些替代成功了,不仅仅是前面的替换。因此,总是用假的t清除'后跟一个':清除'下一个行,重置“t吨'在需要时标记。

其次,你不能依赖塞德在每一个新的循环。

上述脚本的一个可移植实现是:

t清除:清除s/keep-me/keep/gt端s/.*/删除/g:完
塞德(‘w个’)

当脚本包含多个命令以向同一脚本写入行时输出文件,BusyBox塞德错误地打开单独的输出每个命令的流。这可能导致其中一个命令“获胜”而其他人则“输”了,也就是说他们的输出被丢弃了。例如:

sed-n-e’/带xxx/带xxx'<<EOFb条电动势

这可能只输出“'至xxx个'b条'已丢失。为了避免这个问题,可移植脚本最多应该包含一个w个'或's/…//w个'每个输出文件的命令。

睡觉

使用睡觉通常是便携式的。然而,请记住添加睡觉解决时间戳问题1秒的粒度对于并行构建来说不太合适具有亚秒级工艺完成的现代机器。

分类

请记住,排序顺序受当前区域设置的影响。内部配置,C语言环境有效,但在Makefile片段中,您可能需要指定LC_ALL=C排序.

焦油

有多种文件格式焦油如果您使用Automake,AM_INIT_AUTOMAKE公司有一些选项可以控制要使用的可移植性级别。

触摸

如果指定所需的时间戳(例如,使用-第页选项),较旧触摸实现使用美国实用程序系统调用,这可能导致相同类型的时间戳截断问题cp-p'具有。

信托收据

并非所有版本的信托收据处理所有反斜杠字符转义。例如,Solaris 10/usr/ucb/tr虽然摔倒了Solaris包含更现代的信托收据在其他位置。使用八进制转义更便于回车,因为\015'对于ASCII和EBCDIC都是一样的,因为使用脚本中的文字回车会导致许多其他问题。但对于其他字符,如换行符,使用八进制转义会将操作转换为ASCII,因此最好使用文字字符。

${echo moon;echo light;}|/usr/ucb/tr-d“\n”;回声${echo moon;echo light;}|/usr/bin/tr-d“\n”;回声月光${echo moon;echo light;}|/usr/ucb/tr-d'\012';回声月光$nl='
'; {echo moon;echo light;}|/usr/ucb/tr-d“$nl”;回声月光

并非所有版本的信托收据识别字符的直接范围:在最少Solaris/usr/bin/tr仍然没有做到。但你可以使用/usr/xpg4/bin/tr或者添加括号(在Posix中音译)。

$echo“Hazy Fantazy”|LC_ALL=C/usr/bin/tr a-z a-z危险FAntAZy$echo“Hazy Fantazy”|LC_ALL=C/usr/bin/tr'[a-z]''[a-z]'朦胧的幻想$echo“Hazy Fantazy”|LC_ALL=C/usr/xpg4/bin/tr a-z a-z朦胧的幻想

提供两个参数时,确保第二个字符串至少为和第一个一样长。

$echo abc |/usr/xpg4/bin/tr bc d模数转换器$echo abc | coreutils/tr bc d添加

在使用BusyBox工具的平台上,信托收据不支持[x个*n个]选项语法。

$echo abc|tr“abcd”“[A*4]”[答:]*$echo abc | coreutils/tr“abcd”“[A*4]”美国汽车协会$echo xyz|tr“a-z”“[a*]”]]]$echo xyz | coreutils/tr“a-z”“[a*]”美国汽车协会

Posix需要信托收据对二进制文件进行操作。但至少Solaris公司/usr/ucb/tr/usr/bin/tr默默地丢弃NUL(无)在进行任何翻译之前输入。使用时信托收据处理可能包含以下内容的二进制文件NUL(无)字节,有必要使用/usr/xpg4/bin/tr相反,或/usr/xpg6/bin/tr如果可以的话。

$printf“a\0b”|/usr/ucb/tr x x | od-An-tx161 62$printf“a\0b”|/usr/bin/tr x | od-An-tx161 62$printf“a\0b”|/usr/xpg4/bin/tr x | od-An-tx161 00 62

Solaris公司/usr/ucb/tr另外无法处理'\0个'作为的八进制转义NUL(无).

$printf“abc”|/usr/ucb/tr“bc”'\0d”|od-An-tx161 62 63$printf“abc”|/usr/bin/tr“bc”“\0d”| od-安-tx161 00 64$printf“abc”|/usr/xpg4/bin/tr“bc”“\0d”|od-An-tx161 00 64