比如说,以下是一个文件的内容
$ 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