在正则表达式模式匹配中转义双引号的正确语法?
Correct Syntax For Escaping Double Quotes in Regex Pattern Match?
我正在尝试获取 vars string 和 string2 中双引号字符之间的第二个子字符串。
我认为问题在于我试图转义双引号的方式。
正确的语法是什么:
#!/bin/bash
# Example strings.
string='"name": "Bash scripting cheatsheet",'
string2='"url": "https://devhints.io/bash"'
# I'm trying to get the 2nd substring between " "
# desired matches:
# string_name_match='Bash scripting cheatsheet'
# string2_url_match='https://devhints.io/bash'
# Attempts: using a pattern var with double quotes escaped.
pattern='\".*\"' # Is the " char escaped correctly?
echo "$string" | awk "/$pattern/{print }" # Is the $pattern var used correctly?
echo "$string2" | awk "/$pattern/{print }"
# 2nd pattern match using the name/url to parse:
name_pattern='^\"name:\"[:space:].*[^\",]'
url_pattern='^\"url\"[:space:]\"^url:.*[^"]'
echo "$string" | awk "/$name_pattern/{print [=10=]}"
echo "$string2" | awk "/$url_pattern/{print [=10=]}"
以下是您在 awk
中的操作方式:
awk -F '"' -v n=2 '{print $(n*2)}' <<< "$string"
Bash scripting cheatsheet
awk -F '"' -v n=2 '{print $(n*2)}' <<< "$string2"
https://devhints.io/bash
解决当前将正则表达式传递给 awk
的问题,由于转义序列的各种问题,通常更容易处理变量而不是 hard-coded 正则表达式模式,并结合测试整行([=15=]
) 反对模式 (~ pattern_variable
),例如:
string='"name": "Bash scripting cheatsheet",'
string2='"url": "https://devhints.io/bash"'
pattern='"([^"]*)".*"([^"]*)"'
$ awk -v ptn="${pattern}" -F'"' '[=10=] ~ ptn {print }' <<< "${string}"
"Bash
$ awk -v ptn="${pattern}" '[=10=] ~ ptn {print }' <<< "${string2}"
"https://devhints.io/bash"
好的,所以我们 awk
使用正则表达式,但我们没有得到我们想要的,因为默认情况下 awk
使用白色 space 作为默认字段分隔符。我们可以告诉 awk
使用双引号作为分隔符,并且知道我们想要的值在第二组双引号之间:
$ awk -v ptn="${pattern}" -F'"' '[=11=] ~ ptn {print }' <<< "${string}"
Bash scripting cheatsheet
$ awk -v ptn="${pattern}" -F'"' '[=11=] ~ ptn {print }' <<< "${string2}"
https://devhints.io/bash
'当然,每次我们要解析字符串时都需要生成一个子进程。
有一些(更好的)方法可以在 bash
中解析字符串,而无需产生子进程调用的开销 ...
使用一些基本 bash
正则表达式匹配的想法:
string='"name": "Bash scripting cheatsheet",'
string2='"url": "https://devhints.io/bash"'
pattern='"([^"]*)".*"([^"]*)"'
如果 bash
找到匹配项,它将使用有关匹配项的信息填充 BASH_REMATCH[]
数组,每个捕获组(一组括号内的模式部分)使在数组中增加一个单独的条目。
考虑:
$ [[ "${string}" =~ ${pattern} ]] && string_name_match="${BASH_REMATCH[2]}"
$ typeset -p BASH_REMATCH string_name_match
declare -ar BASH_REMATCH=([0]="\"name\": \"Bash scripting cheatsheet\"" [1]="name" [2]="Bash scripting cheatsheet")
declare -- string_name_match="Bash scripting cheatsheet"
$ echo "${string_name_match}"
Bash scripting cheatsheet
$ [[ "${string2}" =~ ${pattern} ]] && string2_url_match="${BASH_REMATCH[2]}"
$ typeset -p BASH_REMATCH string2_url_match
declare -ar BASH_REMATCH=([0]="\"url\": \"https://devhints.io/bash\"" [1]="url" [2]="https://devhints.io/bash")
declare -- string2_url_match="https://devhints.io/bash"
$ echo "${string2_url_match}"
https://devhints.io/bash
使用您显示的示例,请尝试以下 grep
代码。在 GNU grep
.
中编写和测试
echo "$string" | grep -oP '.*?"[^"]*".*?"\K[^"]*'
Bash scripting cheatsheet
echo "$string2" | grep -oP '.*?"[^"]*".*?"\K[^"]*'
https://devhints.io/bash
说明: 这里使用 GNU grep
。通过 echo
命令打印字符串值并将其作为标准输入发送到 grep
命令。在 grep
命令中使用正则表达式 .*?"[^"]*".*?"\K[^"]*
(在下面解释)来实现所需的输出。
正则表达式的解释(.*?"[^"]*".*?"\K[^"]*
):
.*?" ##using lazy match capability of GNU grep and matching till very first occurrence of " here.
[^"]*" ##Then matching everything just before next occurrence of " including " here.
.*?" ##Using lazy match to match till very next occurrence of " here, which will be 3rd occurrence of ".
\K ##Now using magical \K option of GNU grep to forget(basically not to print) whatever was matched before.
[^"]* ##Matching everything just before 4th occurrence of " which is required output.
这是另一个简单的解决方案:
使用 gawk
标准 Linux awk
。
FPAT
变量是匹配数据字段的正则表达式。
echo '"url": "https://devhints.io/bash"' |awk -vFPAT='[^\"]*' '{print }'
https://devhints.io/bash
您可以使用 Bash 正则表达式:
$ [[ $string =~ ^([^\"]*\"){4} ]] && echo "${BASH_REMATCH[1]%\"}"
Bash scripting cheatsheet
$ [[ $string2 =~ ^([^\"]*\"){4} ]] && echo "${BASH_REMATCH[1]%\"}"
https://devhints.io/bash
或与sed
相同的方法:
sed -E 's/^([^"]*\"){4}//; s/".*//' <<<"$string"
Bash scripting cheatsheet
sed -E 's/^([^"]*\"){4}//; s/".*//' <<<"$string2"
https://devhints.io/bash
(但是 sed
不需要转义 "
...)
我正在尝试获取 vars string 和 string2 中双引号字符之间的第二个子字符串。
我认为问题在于我试图转义双引号的方式。
正确的语法是什么:
#!/bin/bash
# Example strings.
string='"name": "Bash scripting cheatsheet",'
string2='"url": "https://devhints.io/bash"'
# I'm trying to get the 2nd substring between " "
# desired matches:
# string_name_match='Bash scripting cheatsheet'
# string2_url_match='https://devhints.io/bash'
# Attempts: using a pattern var with double quotes escaped.
pattern='\".*\"' # Is the " char escaped correctly?
echo "$string" | awk "/$pattern/{print }" # Is the $pattern var used correctly?
echo "$string2" | awk "/$pattern/{print }"
# 2nd pattern match using the name/url to parse:
name_pattern='^\"name:\"[:space:].*[^\",]'
url_pattern='^\"url\"[:space:]\"^url:.*[^"]'
echo "$string" | awk "/$name_pattern/{print [=10=]}"
echo "$string2" | awk "/$url_pattern/{print [=10=]}"
以下是您在 awk
中的操作方式:
awk -F '"' -v n=2 '{print $(n*2)}' <<< "$string"
Bash scripting cheatsheet
awk -F '"' -v n=2 '{print $(n*2)}' <<< "$string2"
https://devhints.io/bash
解决当前将正则表达式传递给 awk
的问题,由于转义序列的各种问题,通常更容易处理变量而不是 hard-coded 正则表达式模式,并结合测试整行([=15=]
) 反对模式 (~ pattern_variable
),例如:
string='"name": "Bash scripting cheatsheet",'
string2='"url": "https://devhints.io/bash"'
pattern='"([^"]*)".*"([^"]*)"'
$ awk -v ptn="${pattern}" -F'"' '[=10=] ~ ptn {print }' <<< "${string}"
"Bash
$ awk -v ptn="${pattern}" '[=10=] ~ ptn {print }' <<< "${string2}"
"https://devhints.io/bash"
好的,所以我们 awk
使用正则表达式,但我们没有得到我们想要的,因为默认情况下 awk
使用白色 space 作为默认字段分隔符。我们可以告诉 awk
使用双引号作为分隔符,并且知道我们想要的值在第二组双引号之间:
$ awk -v ptn="${pattern}" -F'"' '[=11=] ~ ptn {print }' <<< "${string}"
Bash scripting cheatsheet
$ awk -v ptn="${pattern}" -F'"' '[=11=] ~ ptn {print }' <<< "${string2}"
https://devhints.io/bash
'当然,每次我们要解析字符串时都需要生成一个子进程。
有一些(更好的)方法可以在 bash
中解析字符串,而无需产生子进程调用的开销 ...
使用一些基本 bash
正则表达式匹配的想法:
string='"name": "Bash scripting cheatsheet",'
string2='"url": "https://devhints.io/bash"'
pattern='"([^"]*)".*"([^"]*)"'
如果 bash
找到匹配项,它将使用有关匹配项的信息填充 BASH_REMATCH[]
数组,每个捕获组(一组括号内的模式部分)使在数组中增加一个单独的条目。
考虑:
$ [[ "${string}" =~ ${pattern} ]] && string_name_match="${BASH_REMATCH[2]}"
$ typeset -p BASH_REMATCH string_name_match
declare -ar BASH_REMATCH=([0]="\"name\": \"Bash scripting cheatsheet\"" [1]="name" [2]="Bash scripting cheatsheet")
declare -- string_name_match="Bash scripting cheatsheet"
$ echo "${string_name_match}"
Bash scripting cheatsheet
$ [[ "${string2}" =~ ${pattern} ]] && string2_url_match="${BASH_REMATCH[2]}"
$ typeset -p BASH_REMATCH string2_url_match
declare -ar BASH_REMATCH=([0]="\"url\": \"https://devhints.io/bash\"" [1]="url" [2]="https://devhints.io/bash")
declare -- string2_url_match="https://devhints.io/bash"
$ echo "${string2_url_match}"
https://devhints.io/bash
使用您显示的示例,请尝试以下 grep
代码。在 GNU grep
.
echo "$string" | grep -oP '.*?"[^"]*".*?"\K[^"]*'
Bash scripting cheatsheet
echo "$string2" | grep -oP '.*?"[^"]*".*?"\K[^"]*'
https://devhints.io/bash
说明: 这里使用 GNU grep
。通过 echo
命令打印字符串值并将其作为标准输入发送到 grep
命令。在 grep
命令中使用正则表达式 .*?"[^"]*".*?"\K[^"]*
(在下面解释)来实现所需的输出。
正则表达式的解释(.*?"[^"]*".*?"\K[^"]*
):
.*?" ##using lazy match capability of GNU grep and matching till very first occurrence of " here.
[^"]*" ##Then matching everything just before next occurrence of " including " here.
.*?" ##Using lazy match to match till very next occurrence of " here, which will be 3rd occurrence of ".
\K ##Now using magical \K option of GNU grep to forget(basically not to print) whatever was matched before.
[^"]* ##Matching everything just before 4th occurrence of " which is required output.
这是另一个简单的解决方案:
使用 gawk
标准 Linux awk
。
FPAT
变量是匹配数据字段的正则表达式。
echo '"url": "https://devhints.io/bash"' |awk -vFPAT='[^\"]*' '{print }'
https://devhints.io/bash
您可以使用 Bash 正则表达式:
$ [[ $string =~ ^([^\"]*\"){4} ]] && echo "${BASH_REMATCH[1]%\"}"
Bash scripting cheatsheet
$ [[ $string2 =~ ^([^\"]*\"){4} ]] && echo "${BASH_REMATCH[1]%\"}"
https://devhints.io/bash
或与sed
相同的方法:
sed -E 's/^([^"]*\"){4}//; s/".*//' <<<"$string"
Bash scripting cheatsheet
sed -E 's/^([^"]*\"){4}//; s/".*//' <<<"$string2"
https://devhints.io/bash
(但是 sed
不需要转义 "
...)