在 POSIX sh 中替代 Bash 的 [[ ... ]]:脚本兼容性实践
文章正文 markdown 格式数据
POSIX sh 中替代使用 Bash 的[[ ... ]]的方法
提问:
我正在使用以下代码来解析传递给脚本的第一个参数。它具有错误处理功能,并且工作方式完全符合我的要求:
现在我希望使这个脚本符合 POSIX 标准,因此不能使用[[ ]]这个 Bash 特有的语法。我应该如何实现这一点?使用复杂的 case 语句吗?肯定有更好的方法。
答案 2(得分:7)
expr和awk是两个可以进行正则表达式匹配的 POSIX 工具。expr使用基本正则表达式¹,awk使用扩展正则表达式的变体²。expr存在许多设计缺陷,通常被认为已过时(甚至 POSIX 也建议不要使用它),因此最好避免使用。虽然几个 shell(至少是 zsh 和 yash)的[(即test)内置函数可以通过=~操作符进行正则表达式匹配,但这是 POSIX 标准之外的扩展,因此不能在 sh 脚本中使用。在这里,您可以定义使用awk进行正则表达式匹配的 shell 辅助函数match(以及用于不区分大小写变体的imatch):
请注意,严格来说,imatch并不是进行不区分大小写匹配的适当方法,但对于仅 ASCII 输入和正则表达式来说已经足够好了。在这里,使用case结构可能同样简单,并且使其更清晰:
您也可以先删除一个或两个前导的-并转换为小写:
这里使用awk的tolower()进行大小写转换。POSIX 工具集中的替代方案包括dd conv=lcase和tr '[:upper:]' '[:lower:]',但在 GNU 工具集中,截至撰写本文时,只有awk版本适用于多字节字符。³请注意,[[...]]结构最初来自 ksh,而不是 bash。它已被包括 zsh、bash、yash、busybox ash 在内的几个 shell 复制,并有许多变体。其中的正则表达式匹配首先于 2004 年在 zsh 中添加了-pcre-match操作符(PCRE 具有不区分大小写匹配的语法),然后是 bash 于 2005 年在 3.1 版本中添加了=~⁴(进行 ERE 匹配)。后来=~被添加到更多 shell 中,包括 zsh 和 ksh93。在 zsh 中,对于=~,您可以通过(取消)设置rematchpcre选项来选择 ERE 或 PCRE。ksh93 的模式匹配在 2006 年的 ksh93r+版本中扩展为具有正则表达式匹配语法⁵,因此例如您可以执行[[ $action = ~(Ei)^-{0,2}h(elp)?$ ]](在zmodload zsh/pcre之后,相当于 zsh 的[[ $action -pcre-match '(?i)^-{0,2}h(elp)$' ]])。
¹ 使用其:操作符。另请注意,expr正则表达式匹配隐式地在开头锚定(就像有一个隐藏的^),而不是在结尾。² 除了标准 ERE 外,还识别像\n/\b/\123...这样的内容,这意味着除了 busybox awk 之外,您无法获得反向引用(标准 ERE 中也没有反向引用)。请注意,对区间操作符({x,y})的支持在一些 awk 实现中相对较晚才添加(就 mawk 而言是非常近期)。³ 不过,已知一些 GNU/Linux 发行版维护了解决此问题的补丁,因此您的体验可能有所不同。请注意,Ubuntu 上的默认 awk 实现 mawk 也不支持多字节字符。⁴ =~可能源自 perl 中的相同操作符,而 perl 又可能源自 awk 的~操作符。⁵ 本质上,其=~操作符在底层执行一个前面附加了~(E)的模式=。更多精彩内容 请关注我的个人公众号 公众号(办公 AI 智能小助手)对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)
公众号二维码
公众号二维码







评论