匹配文本后在大括号内提取字符串并存储为变量

时间:2018-12-18 20:09:41

标签: bash shell unix awk

我的文件中有几行,如下所示

DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('SUN') NAME('CAT') TRASMIT('TRUCK') REPLACE

括号内的文本对于每一行都会改变。我正在尝试在MANAGER(在本例中为SUN)之后的括号内提取文本,将其存储为变量,然后用planet.SUN.star替换。

我尝试使用awk字段分隔符来提取括号之间的文本,并使用字段分隔符作为括号,但是我的结果不一致。有时,匹配字词MANAGER之后的括号内没有文字。

期望输出如下所示

 DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('PLANET.SUN.STAR') NAME('CAT') TRASMIT('TRUCK') REPLACE

3 个答案:

答案 0 :(得分:1)

如果您选择Task,请尝试:

Perl

输出:

word="MANAGER"
replacement="PLANET.SUN.STAR"
perl -pe "s/(?<=${word}\(')(.+?)(?='\))/${replacement}/" <<< "DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('SUN') NAME('CAT') TRASMIT('TRUCK') REPLACE"
  • 正则表达式DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('PLANET.SUN.STAR') NAME('CAT') TRASMIT('TRUCK') REPLACE 是一个与(?<=${word}\(')匹配的后置断言。
  • 正则表达式MANAGER('是匹配(?='\))/的先行断言。
  • 介于两者之间的正则表达式')是要替换的模式。

我认为您不必仅为替换目的而分配(.+?)变量,但是如果需要,修改代码很容易。

编辑

以下是根据OP的要求而更新的版本。

SUN

输入文字:

perl -pe "s/(?<=MANAGER\(')(.+?)(?='\))/PLANET.\$1.STAR/" text

输出:

DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('SUN') NAME('CAT') TRASMIT('TRUCK') REPLACE
DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('MOON') NAME('CAT') TRASMIT('TRUCK') REPLACE
DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('JUPITER') NAME('CAT') TRASMIT('TRUCK') REPLACE
  • 首先,让我们专注于DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('PLANET.SUN.STAR') NAME('CAT') TRASMIT('TRUCK') REPLACE DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('PLANET.MOON.STAR') NAME('CAT') TRASMIT('TRUCK') REPLACE DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('PLANET.JUPITER.STAR') NAME('CAT') TRASMIT('TRUCK') REPLACE 部分,并将字符串分成三部分:MANAGER('blah')MANAGER('blah
  • 正则表达式')与第一个匹配。正则表达式(?<=MANAGER\(')称为断言为零宽度的正向后断言。它用作 anchor ,并且匹配的字符串包含在捕获组中。该性质对于重新使用原始子字符串(第一部分)而不影响效果很有用。
  • 正则表达式(?<=pattern)与第3个匹配。正则表达式(?='\))是一个零宽度正向超前断言,与第一个正则表达式类似。
  • 正则表达式(?=pattern)与被第一个正则表达式和第三个正则表达式包围的子字符串匹配。量词(.+?)之后的?导致最短匹配,否则正则表达式将尝试在单词边界上尽可能长地匹配。
  • 让我们继续进行REPLACEMENT部分。我们要在捕获的单词之前添加+,并在单词之后添加PLANET..STAR可以引用捕获的单词,然后替换部分看起来像$1。因为脚本在双引号内,所以必须使用反斜杠。

以下是一个PLANET.\$1.STAR版本,它会产生相同的结果:

AWK

希望这符合要求。

答案 1 :(得分:0)

awk解决方案:

echo "DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('SUN') NAME('CAT') TRASMIT('TRUCK') REPLACE" \
| awk '{
    # Look for the field starting with MANAGER(
    for ( I=1 ; I <= NF ; I++ ) {
      if ( $I ~ /^MANAGER[(]/ ){
        MANAGER = $I
        break
      }
    }

    # Remove everything except our value
    sub( /^MANAGER[(]\x27/, "", MANAGER )
    sub( /\x27[)]$/, "", MANAGER )

    # Rebuild the line with the new value
    $I = "MANAGER(\x27PLANET." MANAGER ".STAR\x27)"
    print
  }'

答案 2 :(得分:0)

这与sed并用标准替代形式sed "s/find/replace/"使用捕获组后向引用相当简单,其中{ {1}}包含捕获组find"MANAGER('\(.[^']*\)':使用后向引用 replace插入捕获的内容,例如

\1

通过您的示例,您将获得:

sed "s/MANAGER('\(.[^']*\)')/MANAGER('PLANET.\1.STAR')/"

要在变量中捕获$ echo "DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('SUN') NAME('CAT') TRASMIT('TRUCK') REPLACE" | \ sed "s/MANAGER('\(.[^']*\)')/MANAGER('PLANET.\1.STAR')/" DEF QR('xxx.yyy.sss') USE(YES) DESC('Something') MANAGER('PLANET.SUN.STAR') NAME('CAT') TRASMIT('TRUCK') REPLACE ,您可以将命令替换"SUN"和类似的正则表达式一起使用,后跟参数扩展修剪外部单引号,例如

grep -o

输出结果:

var=$(echo "your_string" | grep -o "MANAGER('.[^']*')")
var="${var#*\'}"
var="${var%\'*}"
echo "var: $var"