解释

解释

比如说,以下是一个文件的内容

$ cat file
Name=Tom
Value=10
Name=Tom
Name=Harry
Value=20

在某些情况下,值不会出现在名称之后。所以我需要做的是找到 Name=Tom 模式并替换值,但前提是出现在紧随名称之后的行中。怎么做?

答案1

awk

awk 'prev ~ /^Name=(Tom|Anything)$/ && /^Value=/ {$0 = "Value=123"}
     {print; prev = $0}'

或者与 姓名和新的价值存储在变量中:

export NAME=Tom VALUE=123
awk 'prev == "Name=" ENVIRON["NAME"] && /^Value=/ {
       $0 = "Value=" ENVIRON["VALUE"]
     }
     {print; prev = $0}'

对于sed,等效项将类似于:

sed -e 'x;/^Name=Tom$/{g;/^Value/s/=.*/=123/;h;b' -e '}' -e g

尽管与往常一样,它比awk.此外,要处理存储在变量中的任意值,sed不具备awk's的等效ENVIRON功能,也不具备进行简单字符串比较(与正则表达式匹配相反)的能力,因此您需要预处理 的值首先是变量,除非你能保证变量不包含sed.

sed -e "x;/^Name=$NAME\$/{g;/^Value/s/=.*/=$VALUE/;h;b" -e '}' -e g

如果和没有受到严格控制,将是一个命令注入漏洞(至少对于 GNU 而言sed) 。$NAME$VALUE

答案2

更紧凑、更简单:

sed 'G;/^Value=/s/=.*\nName=Tom/=42/;s/\n.*//;h' file

这会将保留空间中的前一行附加到每行。对于行,如果该值位于保留空间中,Value=则该值将被替换。Name=Tom否则,附加的行将被删除,并将该行存储在保留空间中以供下一个周期使用。

答案3

sed -e '
   /^Name=Tom$/!b
   $!N
   /\(\nValue\)=.*/s//\1=NEW_VALUE/
   P;D
' data.inp

解释

  • 它将查找其中包含名称 Tom 的行。不匹配将转到标准输出。
  • 然后,如果它不是最后一行,它将尝试将下一行追加到模式空间中。
  • 将在刚刚附加的行中查找正则表达式 Value=,如果是,则该值将更改为 NEW_VALUE (您应该将其更改为您需要的任何内容)。
  • P;D => 将打印 \n 左侧的模式空间部分,即 Name=Tom 的上一行,然后删除该部分。我们现在只剩下 Value=NEW_VALUE ,这样它就会跳转到 sed 脚本行的开头: /^Name=Tom$/!b 显然这会失败,因此将被带到标准输出。这样做是为了处理连续的 Name=Tom 行。

结果

Name=Tom
Value=NEW_VALUE
Name=Tom
Name=Harry
Value=20

相关内容