【问题标题】:How to get a part of a string with a regular expression in a /bin/sh script如何在 /bin/sh 脚本中使用正则表达式获取字符串的一部分
【发布时间】:2014-05-08 15:34:45
【问题描述】:

我需要在 shell 脚本中提取字符串的一部分。原始字符串非常复杂,所以我真的需要一个正则表达式来选择原始字符串的正确部分——仅仅删除前缀和后缀是行不通的。此外,正则表达式需要检查我要提取的字符串的上下文,所以我例如需要一个正则表达式a\([^b]*\)b12a123b23 中提取123

shell 脚本需要可移植,因此我无法使用 Bash 构造 [[BASH_REMATCH

我希望脚本健壮,所以当正则表达式不匹配时,脚本应该注意到这一点,例如通过要使用的命令的非零退出代码。

有什么好的方法可以做到这一点?


我尝试了各种工具,但没有一个能完全解决问题:

  • expr match "$original" ".*$regex.*" 工作,除了错误情况。使用此命令,我不知道如何检测正则表达式是否不匹配。此外,expr 似乎采用提取的字符串来确定其退出代码 - 所以当我碰巧提取 00 时,expr 的退出代码为 1。所以我通常需要使用 expr match "$original" ".*$regex.*" || true 忽略退出代码

  • echo "$original" | sed "s/.*$regex.*/\\1/" 也适用,但错误情况除外。为了处理这种情况,我需要测试我是否找回了原始字符串,这也很不雅。

那么,没有更好的方法吗?

【问题讨论】:

  • 你试过echo $original | grep -o $regex我认为确实如此,-o 只打印匹配的正则表达式部分。
  • 你能提供一些输入字符串的样本和你预期的匹配吗?
  • @MikeH-R, grep -o 是 GNUism,而不是便携式 POSIX 指定的选项。
  • @CharlesDuffy 谢谢,我不知道,有便携版吗?我只是在谷歌上搜索并找不到。
  • @MikeH-R,不适用于grep,不。你可以用 awk 或 sed 做一些可移植的事情。

标签: regex shell sed


【解决方案1】:

您可以使用sed-n 选项来抑制所有输入行的输出,并将p 选项添加到替代命令中,如下所示:

echo "$original" | sed -n -e "s/.*$regex.*/\1/p"

如果正则表达式匹配,匹配的组像以前一样打印。但现在如果正则表达式不匹配,则不会打印任何内容,您只需测试空字符串。

【讨论】:

  • 可移植(您仍然需要定义操作系统或系统之间的可移植性级别,shell ...)在您的操作字符串之前添加-e。它仍然没有回复关于未能找到模式的请求返回 RC > 0
  • 对,添加了-e。关于返回值:现在只测试结果是否为空。
【解决方案2】:

grep -o 怎么样,唯一可能的问题是可移植性,否则它满足所有要求:

➜  echo "hello and other things" | grep -o hello
hello
➜  echo $?
0
➜  echo "hello and other things" | grep -o nothello
➜  echo $?
1

最好的事情之一是,由于它是 grep,您可以选择您想要的正则表达式,无论是 BRE、ERE 还是 Perl。

【讨论】:

  • ...好吧,对于 POSIX grep,您只能获得 BRE 或 ERE。见pubs.opengroup.org/onlinepubs/009695399/utilities/grep.html
  • 谢谢!我不知道grep -o。不幸的是,我只需要正则表达式中的第 1 组。不幸的是,无法检测到我只想从其内容中提取的部分。我编辑了问题以澄清这一点。
  • 我相信你可以使用 Perl 正则表达式,只需将比赛前的所有内容都放在后面 (?<=like_this) 之后,然后将后面的所有内容放在前面 (?=like_this) 但正如 @CharlesDuffy 提到的那样,这不适用于POSIX grep。
【解决方案3】:

如果 egrep 可用(几乎所有时间)

egrep 'YourPattern' YourFile

egrep "${YourPattern}" YourFile

如果只有 grep 可用

grep -e 'YourPattern' YourFile

您使用经典的[ $? -eq 0 ] 检查命令的状态(还要考虑坏的 YourFile 访问)

对于内容本身,使用 sed 或 awk 提取(针对可移植性问题)(失败测试后)

Content="$( sed -n -e "s/.*\(${YourPattern}\).*/\1/p;q" )"

【讨论】:

    猜你喜欢
    • 2021-12-10
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    • 2015-08-19
    • 1970-01-01
    相关资源
    最近更新 更多