sed:如果找到则如何替换行,如果未找到则如何附加到文件末尾?

sed:如果找到则如何替换行,如果未找到则如何附加到文件末尾?

对于仅包含注释(以 # 开头)和 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

相关内容