如何在shell脚本中使用正则表达式提取字符串?

xkrw2x1b  于 2023-02-13  发布在  Shell
关注(0)|答案(2)|浏览(202)

我想使用正则表达式提取字符串的一部分。例如,如何从$name变量中提取域名?

name='<A HREF="http://www.google.com/">here</A>'

domain_name=...  # apply some regex on $name
flvtvl50

flvtvl501#

使用bash正则表达式:

re="http://([^/]+)/"
if [[ $name =~ $re ]]; then echo ${BASH_REMATCH[1]}; fi

Edit- OP要求解释语法。Regular expression syntax是一个很大的主题,我无法在这里完整地解释,但我将尝试解释足够的内容来理解示例。

re="http://([^/]+)/"

这是一个存储在bash变量re中的正则表达式--即您希望输入字符串匹配的内容,并希望从中提取一个子字符串。

  • http://只是一个字符串-输入字符串必须包含此子字符串,正则表达式才能匹配
  • []通常使用方括号表示“匹配方括号内的任何字符”。因此c[ao]t将匹配“cat”和“cot”。[]中的^字符将其修改为“匹配方括号内的任何字符 * 除外 *。因此在本例中[^/]将匹配除“/"以外的任何字符。
  • 方括号表达式只匹配一个字符。在它的末尾添加一个+表示“匹配前面子表达式的一个或多个”。因此[^/]+匹配所有字符集中的一个或多个,不包括“/"。
  • 在子表达式中加上()圆括号表示您希望保存与该子表达式匹配的任何内容以供以后处理。如果您使用的语言支持这一点,它将提供一些机制来检索这些子匹配项。对于bash,它是BASH_REMATCH数组。
  • 最后,我们在“/”上执行精确匹配,以确保完全匹配到完全限定域名的末尾和后面的“/”

接下来,我们需要根据正则表达式测试输入字符串,看看它是否匹配。我们可以使用bash条件来完成这一任务:

if [[ $name =~ $re ]]; then
    echo ${BASH_REMATCH[1]}
fi

在bash中,[[ ]]指定扩展的条件测试,并且可能包含=~ bash正则表达式运算符。在本例中,我们测试输入字符串$name是否与正则表达式$re匹配。如果匹配,则由于正则表达式的构造,我们保证会有一个子匹配(从圆括号()开始),我们可以使用BASH_REMATCH数组访问它:

  • 这个数组${BASH_REMATCH[0]}的元素0将是正则表达式匹配的整个字符串,即“http://www.google.com/“。
  • 这个数组的后续元素将是子匹配的后续结果。注意你可以在一个正则表达式中有多个子匹配()-BASH_REMATCH元素将依次对应这些子匹配。所以在这个例子中${BASH_REMATCH[1]}将包含“www.google.com“,我认为这是你想要的字符串。

注意,BASH_REMATCH数组的内容只适用于最后一次使用正则表达式=~运算符时,所以如果您继续执行更多的正则表达式匹配,您必须每次都从该数组保存所需的内容。
这可能看起来是一个冗长的描述,但我确实掩盖了正则表达式的几个错综复杂之处。它们可以相当强大,我相信性能也不错,但正则表达式语法很复杂。而且正则表达式的实现也各不相同,因此不同的语言将支持不同的特征并且可能在语法上有细微的差别。特别是正则表达式中的字符转义可能是一个棘手的问题,尤其是当这些字符在给定的语言中具有不同的含义时。
请注意,您可以将正则表达式直接放入条件中,而不是在单独的行中设置$re变量并在条件中引用此变量。但是在bash 3.2中,更改了有关此类文字正则表达式是否需要引号的规则。将正则表达式放入单独的变量中是解决此问题的直接方法。以便该条件在支持=~匹配运算符的所有bash版本中按预期工作。

aamkag61

aamkag612#

一种方法是使用sed。例如:

echo $name | sed -e 's?http://www\.??'

通常,sed正则表达式用'/'分隔,但你可以用'?',因为你要搜索'/'。这里有另一个bash技巧。@DigitalTrauma的回答提醒了我,我应该建议它。它是类似的:

echo ${name#http://www.}

(DigitalTrauma还提醒我需要处理“http://”。)

相关问题