sed:如果找到则如何替换行,或者如果找不到则追加到文件末尾?


34

对于仅包含注释(以#开头)和VARIABLE = value行的单个输入文件,是否可以替换单个变量的值(如果找到),否则,可以将对附加到文件末尾(如果找不到)?

我当前的方法是通过在第一遍中将其删除,然后在第二遍中将其添加到文件末尾的方式来工作的,但是此方法弄乱了行的顺序(也是两个不同的命令):

sed -r "/^FOOBAR=.*$/d"      -i samefile &&
sed -r "$ a\FOOBAR=newvalue" -i samefile

反正有做到这一点,即。在单个sed行中保持行顺序?如果其他实用程序(awk,...)执行此操作,则将其接管sed。

Answers:


29

使用以下命令实际上很简单sed:如果一行匹配,只需将其复制到h旧空间中,然后s将该值进行填充。
在最后$一行上,x更改保留空间和模式空间,然后检查后者是否为空。如果不为空,则表示已进行替换,因此无需执行任何操作。如果为空,则表示未找到匹配项,因此将模式空间替换为所需的variable = value,然后将其追加到保持缓冲区中的当前行。最后,e 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

1
如果newvalue存储在变量中,它将是什么样?
user1810087 '17

sed "/^${varName}=/{h;s/=.*/=${varValue}/};\${x;/^$/{s//${varName}=${varValue}/;H};x}" ${VARFILE}带有变量,双引号以允许变量替换,并$在此时$$varNamesed "/^${varName}=/{h;s/=.*/=${!varName}/};\${x;/^$/{s//${varName}=${!varName}/;H};x}" ${VARFILE}
避开

1
这个解决方案不是“简单”的。但这有效。sed手册页不是最容易筛选的内容,如果您可以详细说明表达式各部分的效果,这将非常有帮助:)
user2066480

18

这可能可以缩短。这不是单个sed命令,它还使用grep,但这基本上就是您想要的。它是一行,它就地编辑文件(没有临时文件)。

grep -q "^FOOBAR=" file && sed "s/^FOOBAR=.*/FOOBAR=newvalue/" -i file || 
    sed "$ a\FOOBAR=newvalue" -i file

13

这是一种更简单的sed方法,因为我觉得不sed hold space容易使用。如果您愿意hold space,可以使用don_crissti方法来保留现有行中的任何内容,但这通常很少见。

在这种方法中,您只打印要删除的行以外的所有行,然后在末尾附加替换行。

sed -n -e '/^FOOBAR=/!p' -e '$aFOOBAR=newvalue' infile

1
如果您计划更新可能具有现有但过时的值的文件,则此版本非常好。
guillem 18年

3

根据其他答案,如果文件中存在该变量,则要替换该变量的值,如果不存在该变量,则将其附加到文件末尾(这不是您发布的sed命令所执行的操作),可以尝试这样:

perl -ne '$c=1 if s/^FOOBAR=.*$/FOOBAR=newvalue/;  
             print; 
             END{print "FOBAR=newvalue" unless $c==1}' file > tmpfile && 
mv tmpfile file

1

尽管“就地编辑”不是自动的,但用awk稍微容易一些:

awk -v varname="FOOBAR" -v newval="newvalue" '
    BEGIN {FS = OFS = "="}
    $1 == varname {$2 = newval; found = 1}
    {print}
    END {if (! found) {print varname, newval}}
' file > tempfile &&
mv tempfile file

1

只需使用grepecho创建一个空记录:

grep -q '^FOOBAR=' somefile || echo 'FOOBAR=VALUE' >> somefile
sed -i 's/FOOBAR=.*$/FOOBAR=VALUE/' somefile 

每行转义错误代码为零。


您会丢失行顺序,同时添加其他命令,grep并且echo
BlakBat

的确,如果您在文件末尾插入新项目,但是如果替换旧值,请保持排序。
MUY比利时

0

实际适用于以下情况: sed -i '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile 在选择的答案中-i丢失。


3
这实际上是评论,而不是原始问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论-您可以随时对自己的帖子发表评论,一旦您拥有足够的声誉,就可以在任何帖子中发表评论。请阅读为什么我需要50个信誉才能发表评论?我该怎么办?
DavidPostill

-1

用perl做到这一点,并就地适合我:

grep ^FOOBAR= my.file && perl -i -ple "s/^FOOBAR=.+/FOOBAR=newvalue/g" my.file || echo FOOBAR=newvalue >> my.file

2
这个答案在很多方面都是不好的grepechoperl不是做任何事情perl?另外,>> my.file正在从文件()读取时写入文件(grep my.file)吗?
vladr
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.