Bash 正则表达式捕获组
Bash Regex Capture Groups
我有一个字符串是这种格式:
"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"
如果我用 JS、C# 等编写普通的正则表达式,我会这样做
(?:"(.+?)"|'(.+?)'|(\S+))
并迭代匹配组以获取每个字符串,最好不带引号。我最终想将每个值添加到数组中,因此在示例中,我最终在数组中得到 3 个项目,如下所示:
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
我不知道如何使用 grep
或 sed
或 bash 正则表达式复制此功能。我试过一些东西,比如
echo "$email" | grep -oP "\"\K(.+?)(?=\")|'\K(.+?)(?=')|(\S+)"
这个问题是虽然它有点模仿捕获组的功能,但它并不真正适用于倍数,所以我得到像
这样的捕获
"Mike
H<michael.haken@email1.com>"
michael.haken@email2.com
如果我删除 look ahead/behind 逻辑,我至少得到 3 个字符串,但第一个和最后一个仍然用引号引起来。在这种方法中,我将输出通过管道传输到 read
,这样我就可以将每个字符串单独添加到数组中,但我对其他选项持开放态度。
编辑:
我认为我的输入示例可能令人困惑,这只是一个可能的输入。实际输入可以是双引号、单引号或非引号(无空格)的字符串,以任意顺序任意数量。 Javascript/C# 我提供的正则表达式是我想要实现的真实行为。
您可以使用 sed
来实现,
$ sed -r 's/"(.*)" (.*)"(.*)"/\n\n/g' <<< "$EMAIL"
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
您可以使用 Perl:
$ email='"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"'
$ echo "$email" | perl -lane 'while (/"([^"]+)"|(\S+)/g) {print ? : }'
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
或者在纯 Bash 中,它有点罗嗦:
re='\"([^\"]+)\"[[:space:]]*|([^[:space:]]+)[[:space:]]*'
while [[ $email =~ $re ]]; do
echo ${BASH_REMATCH[1]}${BASH_REMATCH[2]}
i=${#BASH_REMATCH}
email=${email:i}
done
# same output
使用gawk
可以设置多行RS
。
awk -v RS='"|" ' 'NF' inputfile
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
像这样修改你的正则表达式:
grep -oP '("?\s*)\K.*?(?=")' file
输出:
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
你的第一个表情没问题;请注意引号(当存在 \
时使用单引号)。最后trim用sed."
$ echo $mail | grep -Po '".*?"|\S+' | sed -r 's/"$|^"//g'
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
gawk + bash解决方案(将每一项添加到数组中):
email_str='"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"'
readarray -t email_arr < <(awk -v FPAT="[^\"'[:space:]]+[^\"']+[^\"'[:space:]]+" \
'{ for(i=1;i<=NF;i++) print $i }' <<<$email_str)
现在,所有项目都在 email_arr
正在访问第二项:
echo "${email_arr[1]}"
michael.haken@email2.com
正在访问第 3 项:
echo "${email_arr[3]}"
Mike H<hakenmt@email1.com>
使用 GNU awk 和 FPAT
到 define fields by content:
$ awk '
BEGIN { FPAT="([^ ]*)|(\"[^\"]*\")" } # define a field to be space-separated or in quotes
{
for(i=1;i<=NF;i++) { # iterate every field
gsub(/^\"|\"$/,"",$i) # remove leading and trailing quotes
print $i # output
}
}' file
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
我能够做到的是可行的,但不如我希望的代码那样简洁:
arr=()
while read line; do
line="${line//\"/}"
arr+=("${line//\'/}")
done < <(echo $email | grep -oP "\"(.+?)\"|'(.+?)'|(\S+)")
这给了我一个捕获组的数组,并以任何顺序处理输入,用双引号或单引号引起来,如果没有 space,则完全用 none 引起来。它还提供了数组中没有引号的元素。感谢所有的建议。
我有一个字符串是这种格式:
"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"
如果我用 JS、C# 等编写普通的正则表达式,我会这样做
(?:"(.+?)"|'(.+?)'|(\S+))
并迭代匹配组以获取每个字符串,最好不带引号。我最终想将每个值添加到数组中,因此在示例中,我最终在数组中得到 3 个项目,如下所示:
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
我不知道如何使用 grep
或 sed
或 bash 正则表达式复制此功能。我试过一些东西,比如
echo "$email" | grep -oP "\"\K(.+?)(?=\")|'\K(.+?)(?=')|(\S+)"
这个问题是虽然它有点模仿捕获组的功能,但它并不真正适用于倍数,所以我得到像
这样的捕获"Mike
H<michael.haken@email1.com>"
michael.haken@email2.com
如果我删除 look ahead/behind 逻辑,我至少得到 3 个字符串,但第一个和最后一个仍然用引号引起来。在这种方法中,我将输出通过管道传输到 read
,这样我就可以将每个字符串单独添加到数组中,但我对其他选项持开放态度。
编辑:
我认为我的输入示例可能令人困惑,这只是一个可能的输入。实际输入可以是双引号、单引号或非引号(无空格)的字符串,以任意顺序任意数量。 Javascript/C# 我提供的正则表达式是我想要实现的真实行为。
您可以使用 sed
来实现,
$ sed -r 's/"(.*)" (.*)"(.*)"/\n\n/g' <<< "$EMAIL"
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
您可以使用 Perl:
$ email='"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"'
$ echo "$email" | perl -lane 'while (/"([^"]+)"|(\S+)/g) {print ? : }'
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
或者在纯 Bash 中,它有点罗嗦:
re='\"([^\"]+)\"[[:space:]]*|([^[:space:]]+)[[:space:]]*'
while [[ $email =~ $re ]]; do
echo ${BASH_REMATCH[1]}${BASH_REMATCH[2]}
i=${#BASH_REMATCH}
email=${email:i}
done
# same output
使用gawk
可以设置多行RS
。
awk -v RS='"|" ' 'NF' inputfile
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
像这样修改你的正则表达式:
grep -oP '("?\s*)\K.*?(?=")' file
输出:
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
你的第一个表情没问题;请注意引号(当存在 \
时使用单引号)。最后trim用sed."
$ echo $mail | grep -Po '".*?"|\S+' | sed -r 's/"$|^"//g'
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
gawk + bash解决方案(将每一项添加到数组中):
email_str='"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"'
readarray -t email_arr < <(awk -v FPAT="[^\"'[:space:]]+[^\"']+[^\"'[:space:]]+" \
'{ for(i=1;i<=NF;i++) print $i }' <<<$email_str)
现在,所有项目都在 email_arr
正在访问第二项:
echo "${email_arr[1]}"
michael.haken@email2.com
正在访问第 3 项:
echo "${email_arr[3]}"
Mike H<hakenmt@email1.com>
使用 GNU awk 和 FPAT
到 define fields by content:
$ awk '
BEGIN { FPAT="([^ ]*)|(\"[^\"]*\")" } # define a field to be space-separated or in quotes
{
for(i=1;i<=NF;i++) { # iterate every field
gsub(/^\"|\"$/,"",$i) # remove leading and trailing quotes
print $i # output
}
}' file
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
我能够做到的是可行的,但不如我希望的代码那样简洁:
arr=()
while read line; do
line="${line//\"/}"
arr+=("${line//\'/}")
done < <(echo $email | grep -oP "\"(.+?)\"|'(.+?)'|(\S+)")
这给了我一个捕获组的数组,并以任何顺序处理输入,用双引号或单引号引起来,如果没有 space,则完全用 none 引起来。它还提供了数组中没有引号的元素。感谢所有的建议。