对于仅包含注释(以 # 开头)和 VARIABLE=value 行的单个输入文件,是否可以在找到单个变量时将其值替换,否则,如果未找到,则将该对附加到文件末尾?
我当前的方法是先在第一次传递中删除它,然后在第二次传递中将其附加到文件末尾,但是这种方法会弄乱行序(并且也是两个不同的命令):
sed -r "/^FOOBAR=.*$/d" -i samefile &&
sed -r "$ a\FOOBAR=newvalue" -i samefile
有没有办法做到这一点,即在单个 sed 行中保持行顺序?如果其他实用程序 (awk,...) 可以做到这一点,我会选择它而不是 sed。
答案1
实际上,使用 非常简单sed
:如果一行匹配,只需将其复制到h
旧空间,然后s
替换该值。
在最后$
一行,x
更改保存空间和模式空间,然后检查后者是否为空。如果它不为空,则意味着替换已经完成,因此无需执行任何操作。如果它为空,则意味着未找到匹配项,因此将模式空间替换为所需的变量=值然后将其附加到保留缓冲区的当前行。最后,x
再次更改:
sed '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile
以上是gnu sed
语法。可移植:
sed '/^FOOBAR=/{
h
s/=.*/=newvalue/
}
${
x
/^$/{
s//FOOBAR=newvalue/
H
}
x
}' infile
答案2
这是一个更简单的sed
方法,因为我发现它不太sed
hold space
容易使用。如果您习惯使用hold space
,使用 don_crissti 的方法可以为您提供更多机会来保留现有线路及其位置的任何内容。
在下面的方法中,您只需打印除了要删除的行之外的所有内容,然后在最后附加替换行。
sed -n -e '/^FOOBAR=/!p' -e '$aFOOBAR=newvalue' infile
正如@alek 指出的那样,该行被移动到文件末尾,因此请确保在您的情况下这是可以接受的。
答案3
这可能可以缩短。它不是单个 sed 命令,它还使用 grep,但这似乎基本上就是您想要的。它只有一行,并且它会就地编辑文件(没有临时文件)。
grep -q "^FOOBAR=" file && sed "s/^FOOBAR=.*/FOOBAR=newvalue/" -i file ||
sed "$ a\FOOBAR=newvalue" -i file
答案4
根据其他答案,如果您想要做的是如果文件中存在该变量则替换该变量的值,如果不存在则将其附加到文件末尾(这不是您发布的sed
命令所做的),您可以尝试这个:
perl -ne '$c=1 if s/^FOOBAR=.*$/FOOBAR=newvalue/;
print;
END{print "FOOBAR=newvalue" unless $c==1}' file > tmpfile &&
mv tmpfile file