我偶然发现了以下sed
命令的一个小问题,该命令去掉了一行的前导和尾部空格字符,并将其封装在双引号中:
printf '%sn' ' hello ' ' hello' 'hello ' hello | sed -E 's/^ *| *$/"/g'
结果是:
- 在Linux上:
"hello"
"hello"
"hello"
"hello"
- 在macOS上:
"hello"
"hello
"hello"
"hello
FreeBSD上的"hello"
"
"hello"
"hello"
我并不是真的在寻找解决方案,因为我有适用于所有平台的解决方案(不过我对其他方案持开放态度(:
sed 's/^ */"/;s/ *$/"/'
awk '{gsub(/^ *| *$/,""")}1' # the culprit works fine with awk
我的问题是:我对sed命令的理解是错误的吗?或者这可以被认为是macOS和FreeBSDsed
实现中的一个错误吗?
Sed实现差异很大
sed有很多不同的版本,通常情况下,你不应该期望不同版本之间有标准化的行为,尤其是在不同的操作系统上。sed常见问题解答可以说已经过时了,但它很好地说明了有多少不同的实现。Open Group还提供了sed的基本规范,这主要是因为不包括-E
标志和对扩展正则表达式(ERE(的支持。
GNU sed可以说更具可移植性,因为它可以被编译,并且在任何可以使用GCC构建的系统上都会有类似的行为,任何所需的扩展,如ERE和PCRE支持,并且行结尾相同或在表达式中正确解释。由于大多数sed实现实际上都是POSIX规范的超集,因此在其他方面,您将受制于您所使用的特定sed:
- 实际的POSIX合规性,因为并非所有的shell、OS或userland工具都旨在完全符合POSIX,无论是否带有标志;以及
- 您的特定用例或表达式可能需要的任何附加功能
如果可移植性是一个主要问题,并且你不能依赖GNU sed,那么你可能想看看你是否可以依赖其他类似sed的超集,比如Perl或Ruby模式,它们使用命令行标志来进行面向行的处理,但背后有更强大的正则表达式引擎。