【问题标题】:How to extract part of string in Bash using regex如何使用正则表达式在 Bash 中提取部分字符串
【发布时间】:2021-11-26 18:50:51
【问题描述】:

我一直试图在 bash 中提取部分字符串。我在 Mac 上使用它。

输入字符串的模式:

  • 一些随机词后跟/。这是可选的。
  • 关键字(deffoobar)后跟连字符(-)后跟数字。这可以是 2-6 位数字
  • 这些数字后面又是连字符和几个连字符分隔的单词。

示例输入和输出:

abc/def-1234-random-words // def-1234
bla/foo-12-random-words // foo-12
bar-12345-random-words // bar-12345

所以我尝试使用以下命令来获取它,但由于某种奇怪的原因,它返回了整个字符串。

extractedValue=`getInputString | sed -e 's/.*\(\(def\|bar\|foo\)-[^-]*\).*/\1/g'`
// and
extractedValue=`getInputString | sed -e 's/.*\(\(def\|bar\|foo\)-\d{2,6}\).*/\1/g'`

我还尝试使用I 标志使其不区分大小写,但它给我抛出了错误:

:替代命令中的错误标志:'I'


以下是我尝试过的参考:

【问题讨论】:

  • sed 不支持\d 用于数字,你可以使用[0-9]
  • @Barmar 我注意到\d 周围有一些奇怪的行为。因此我搬到了[^-]*。它曾经匹配它,但总是返回整个字符串。但我会阅读更多关于它的内容

标签: regex sed


【解决方案1】:

这个gnu sed 应该与忽略大小写标志一起使用:

sed -E 's~^(.*/){0,1}((def|foo|bar)-[0-9]{2,6})-.*~\2~I' file

def-1234
foo-12
bar-12345

此 sed 匹配:

  • (.*/){0,1}:匹配一个字符串到 / 可选地在开始
  • (: 开始捕获组 #2
    • (def|foo|bar):匹配 deffoobar
    • -:匹配一个-
    • [0-9]{2,6}:匹配 2 到 6 位数字
  • ): 结束捕获组 #2
  • -.*: 匹配 - 后跟任何内容直到结束
  • 替代是我们在第 2 组中捕获的价值

或者你可以使用这个awk:

awk -v IGNORECASE=1 -F / 'match($NF, /^(def|foo|bar)-[0-9]{2,6}-/) {print substr($NF, 1, RLENGTH-1)}' file

def-1234
foo-12
bar-12345

Awk 解释:

  • -v IGNORECASE=1:启用忽略大小写匹配
  • -F /:使用/作为字段分隔符
  • match($NF, /^(def|foo|bar)-[0-9]{2,6}-/):在$NF 中使用正则表达式^(def|foo|bar)-[0-9]{2,6}- 匹配文本,这是使用/ 作为字段分隔符的最后一个字段(忽略/ 之前的文本)
  • 如果匹配成功,则使用substr 打印从位置1RLENGTH-1 的文本(因为我们在数字后匹配到-

【讨论】:

  • 能否请您也添加解释? $NF 是什么意思,区分大小写吗?
  • 我要补充。同时检查sed,它会忽略大小写匹配
  • 奇怪的是,sed 方法仍然抛出这个错误::替代命令中的错误标志:'I'。它是特定于环境的吗?我在 Mac 终端上使用 ZSH
  • 是的,正如我提到的,这需要 gnu sed。 Mac 上的 sed 是 BSD,不支持 /I。我也在 Mac 上,但使用 home brew 安装了 gnu sed
【解决方案2】:

您可以使用-E 选项来使用扩展正则表达式,然后您不必转义(|

echo abc/def-1234-random-words  | sed -E -e 's/.*((def|bar|foo)-[^-]*).*/\1/g'
def-1234

【讨论】:

  • 这与gsed 的不区分大小写标志/I 一起解决了我的问题。非常感谢!
猜你喜欢
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 1970-01-01
  • 2017-08-23
  • 1970-01-01
  • 1970-01-01
  • 2012-11-02
相关资源
最近更新 更多