提取分隔符之间的所有事件,因为它们每行可以出现多个
Extract all ocurrences between delimiters being that they can appear more than one per line
我有一个文档 file.yaml,其中包含要替换的占位符之类的内容:
class: ##TOPIC##-area
name: myClass
type: Class
secretKey: private-##SECRET_KEY##
到目前为止,我已经使用 grep 获取占位符的值
grep -P '(?<=##).*(?=##)' file.yaml
然后,我有那些值:
TOPIC
SECRET_KEY
现在,我们必须引入每行可以有多个占位符的新属性
class: ##TOPIC##-area
name: myClass
type: Class
secretKey: private-##SECRET_KEY##-encoded-##SUFFIX_CODE##
因此,grep 不再起作用,因为输出变为:
TOPIC
SECRET_KEY##-encoded-##SUFFIX_CODE
但是,我想要
TOPIC
SECRET_KEY
SUFFIX_CODE
我接受各种建议和想法来解决这个问题。谢谢
编辑:想法是只获取那些占位符,而不是替换它们。抱歉造成误会。
使用否定先行从匹配中排除包含 ##
的子字符串。
(?<=##)((?!##).)*(?=##)
请注意,这也会 return -encoded-
,因为它也在一对 ##
之间。通常您不会得到重叠匹配,但环顾四周不被视为匹配的一部分,因此它们不算作重叠。
当您想使用 grep
时,请尝试使用
grep -Eo "##[^#]*##" file.yaml | tr -d '#'
使用 awk
你可以有一个多字符分隔符,看起来更简单:
awk -F'##' '{for (i=2; i<=NF;i+=2) {print $i}}' file.yaml
如果 sed 是一个选项,您可以尝试这个解决方案:
sed '/##.*##/!d
s/##/\
/
s/.*\n//
s/##/\
/
P;D' file
或者,一个简单的 bash
解决方案:
#!/bin/bash
while read -r line; do
while [[ $line = *'##'*'##'* ]]; do
line=${line#*'##'}
printf '%s\n' "${line%%'##'*}"
line=${line#*'##'}
done
done < file
你得到那个输出的原因是因为 .*
是贪婪的。您可以改为使其非贪婪 .*?
。
如果只想输出匹配,可以在grep中添加-o
。
grep -oP '(?<=##).*?(?=##)' file.yaml
输出
TOPIC
SECRET_KEY
-encoded-
SUFFIX_CODE
如果只有大写占位符且中间可以有下划线,则可以使模式更具体一些。
grep -oP "##\K[A-Z]+(?:_[A-Z]+)*(?=##)" file.yaml
##
字面匹配
\K
忘记目前匹配的内容(清空当前匹配缓冲区)
[A-Z]+(?:_[A-Z]+)*
匹配 1+ 个大写字符,可选地由 _
和大写字符 重复
(?=##)
正面前瞻,向右断言 ##
看到一个regex demo.
输出
TOPIC
SECRET_KEY
SUFFIX_CODE
第一个解决方案: 使用 GNU awk
,请尝试以下 awk
代码。简单的解释是,将 RS(记录分隔符)设置为 ##
,直到下一次出现 #
,然后出现 2 次 ##
。然后根据显示的输出示例,仅通过删除结果中不需要的 ##
来打印匹配的行。
awk -v RS='##[^#]*##' 'RT{print substr(RT,3,length(RT)-4)}' Input_file
第二个解决方案: 对于任何 awk
,请尝试以下程序。简单的解释是,使用 awk
的 match
函数来匹配正则表达式 /##[^#]*##/
(已经在上面的第一个解决方案中解释过);在 while 循环中打印每行中找到的所有匹配项。
awk '{while(match([=11=],/##[^#]*##/)){print substr([=11=],RSTART+2,RLENGTH-4);[=11=]=substr([=11=],RSTART+RLENGTH)}}' Input_file
如果Perl
是您的选择,请您尝试:
perl -lne 'print while /##(.+?)##/g' file.yaml
-l
选项将换行符附加到 print
. 的输出
-ne
选项与 sed
. 的选项大部分相似
</code>指的是正则表达式的捕获组1。</li>
<li><code>while /pattern/g
语法允许在同一行中进行多个匹配。
使用 GNU awk
进行多字符 RS,RT:
awk -v RS='##[[:upper:]_]+##' 'RT{gsub(/##/,"",RT);print RT}' file
TOPIC
SECRET_KEY
SUFFIX_CODE
我有一个文档 file.yaml,其中包含要替换的占位符之类的内容:
class: ##TOPIC##-area
name: myClass
type: Class
secretKey: private-##SECRET_KEY##
到目前为止,我已经使用 grep 获取占位符的值
grep -P '(?<=##).*(?=##)' file.yaml
然后,我有那些值:
TOPIC
SECRET_KEY
现在,我们必须引入每行可以有多个占位符的新属性
class: ##TOPIC##-area
name: myClass
type: Class
secretKey: private-##SECRET_KEY##-encoded-##SUFFIX_CODE##
因此,grep 不再起作用,因为输出变为:
TOPIC
SECRET_KEY##-encoded-##SUFFIX_CODE
但是,我想要
TOPIC
SECRET_KEY
SUFFIX_CODE
我接受各种建议和想法来解决这个问题。谢谢
编辑:想法是只获取那些占位符,而不是替换它们。抱歉造成误会。
使用否定先行从匹配中排除包含 ##
的子字符串。
(?<=##)((?!##).)*(?=##)
请注意,这也会 return -encoded-
,因为它也在一对 ##
之间。通常您不会得到重叠匹配,但环顾四周不被视为匹配的一部分,因此它们不算作重叠。
当您想使用 grep
时,请尝试使用
grep -Eo "##[^#]*##" file.yaml | tr -d '#'
使用 awk
你可以有一个多字符分隔符,看起来更简单:
awk -F'##' '{for (i=2; i<=NF;i+=2) {print $i}}' file.yaml
如果 sed 是一个选项,您可以尝试这个解决方案:
sed '/##.*##/!d
s/##/\
/
s/.*\n//
s/##/\
/
P;D' file
或者,一个简单的 bash
解决方案:
#!/bin/bash
while read -r line; do
while [[ $line = *'##'*'##'* ]]; do
line=${line#*'##'}
printf '%s\n' "${line%%'##'*}"
line=${line#*'##'}
done
done < file
你得到那个输出的原因是因为 .*
是贪婪的。您可以改为使其非贪婪 .*?
。
如果只想输出匹配,可以在grep中添加-o
。
grep -oP '(?<=##).*?(?=##)' file.yaml
输出
TOPIC
SECRET_KEY
-encoded-
SUFFIX_CODE
如果只有大写占位符且中间可以有下划线,则可以使模式更具体一些。
grep -oP "##\K[A-Z]+(?:_[A-Z]+)*(?=##)" file.yaml
##
字面匹配\K
忘记目前匹配的内容(清空当前匹配缓冲区)[A-Z]+(?:_[A-Z]+)*
匹配 1+ 个大写字符,可选地由_
和大写字符 重复
(?=##)
正面前瞻,向右断言##
看到一个regex demo.
输出
TOPIC
SECRET_KEY
SUFFIX_CODE
第一个解决方案: 使用 GNU awk
,请尝试以下 awk
代码。简单的解释是,将 RS(记录分隔符)设置为 ##
,直到下一次出现 #
,然后出现 2 次 ##
。然后根据显示的输出示例,仅通过删除结果中不需要的 ##
来打印匹配的行。
awk -v RS='##[^#]*##' 'RT{print substr(RT,3,length(RT)-4)}' Input_file
第二个解决方案: 对于任何 awk
,请尝试以下程序。简单的解释是,使用 awk
的 match
函数来匹配正则表达式 /##[^#]*##/
(已经在上面的第一个解决方案中解释过);在 while 循环中打印每行中找到的所有匹配项。
awk '{while(match([=11=],/##[^#]*##/)){print substr([=11=],RSTART+2,RLENGTH-4);[=11=]=substr([=11=],RSTART+RLENGTH)}}' Input_file
如果Perl
是您的选择,请您尝试:
perl -lne 'print while /##(.+?)##/g' file.yaml
-l
选项将换行符附加到print
. 的输出
-ne
选项与sed
. 的选项大部分相似
</code>指的是正则表达式的捕获组1。</li> <li><code>while /pattern/g
语法允许在同一行中进行多个匹配。
使用 GNU awk
进行多字符 RS,RT:
awk -v RS='##[[:upper:]_]+##' 'RT{gsub(/##/,"",RT);print RT}' file
TOPIC
SECRET_KEY
SUFFIX_CODE