外壳脚本。如何使用正则表达式提取字符串

Posted

技术标签:

【中文标题】外壳脚本。如何使用正则表达式提取字符串【英文标题】:shell script. how to extract string using regular expressions 【发布时间】:2013-11-13 07:09:10 【问题描述】:

我是 shell 脚本的新手。我想使用 curl 发送一个 http 请求,然后使用正则表达式提取一些字符串。例如,如何从 http 响应中提取域名? (示例仅供学习)

#!/bin/bash
name=$(curl google.com | grep "www\..*com")
echo "domain name is"
echo $name

【问题讨论】:

【参考方案1】:

使用bash regular expressions:

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

编辑 - OP 要求解释语法。 Regular expression syntax 是一个很大的话题,我在这里无法完整地解释,但我会尽量解释得足以理解这个例子。

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

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

http:// 只是一个字符串 - 输入字符串必须包含此子字符串才能匹配正则表达式 [] 通常使用方括号表示“匹配括号内的任何字符”。所以c[ao]t 将匹配“cat”和“cot”。 [] 中的 ^ 字符将其修改为“匹配方括号内的任何字符除了。因此在这种情况下[^/] 将匹配除“/”之外的任何字符。 方括号表达式只能匹配一个字符。在其末尾添加 + 表示“匹配 1 个或多个前面的子表达式”。所以[^/]+ 匹配所有字符集中的一个或多个,不包括“/”。 在子表达式周围加上() 括号表示您希望保存与该子表达式匹配的任何内容以供以后处理。如果您使用的语言支持这一点,它将提供一些机制来检索这些子匹配。对于 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 版本中按预期工作。

【讨论】:

如果您需要进行不区分大小写的匹配或更改其他标志怎么办? 仅供参考 Bash 不理解非捕获组(例如 (?:...))。所以我只使用了我感兴趣的组的索引$BASH_REMATCH[0], Example,\ ``` path=$1 re="(create|identical) (.+)" comp=$(echo $path | awk -F "/" 'print $NF' | awk -F"." 'print $1') res=yo jest:test $path --componentName $comp 2>&1 if [[ $res =~ $re ]];然后 src=$BASH_REMATCH[2] dest=$(echo $src | awk 'sub("__tests__/", ""); print'); dest="tests/$dest" mv $src $dest echo "创建 $dest" fi ```【参考方案2】:

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

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

通常sed 正则表达式由`/' 分隔,但您可以使用'?'因为您正在搜索“/”。这是另一个 bash 技巧。 @DigitalTrauma 的回答提醒我应该提出建议。类似:

echo $name#http://www.

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

【讨论】:

以上是关于外壳脚本。如何使用正则表达式提取字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何使用正则表达式从某些文本中提取脚本标签?

在猪脚本中使用正则表达式从日志中提取字符串

请问正则表达式如何过滤超链接和提取链接

正则表达式从bash脚本中的字符串中提取第一个浮点数

如何使用正则表达式提取部分字符串

如何使用 JavaScript 正则表达式提取字符串?