根据字符串的存在性编辑文件

根据字符串的存在性编辑文件

我有一个输入文件,例如 ,file1其显示如下:

WRITE=2
START=1
SMEAR=0
MIN=6
MAX=100

我的问题是搜索字符串SMEAR,如果字符串存在,则用替换整行SMEAR=-5。但是,如果SMEAR不存在,则我需要插入新行SMEAR=-5。最终该行SMEAR=-5应该只出现一次。我可以使用 sed 替换字符串:

 sed -i '/SMEAR/c\SMEAR=-5' file1

或者我可以将字符串作为新行插入

 sed -i '10i SMEAR=-5' file1

但是我如何根据文件中字符串的存在来组合它们呢?

编辑:SMEAR如果我可以将 的值作为变量 传递,也会很有帮助。

答案1

看起来行的顺序对于您的用例并不重要。鉴于此,我会ex简单地使用:

  1. 删除SMEAR;的所有实例
  2. 插入你想要的行。

你可以这样做:

printf '%s\n' 'g/SMEAR/d' '$a' 'SMEAR=-5' . x | ex file.txt

第一个命令是g全局d删除与 regex 匹配的所有行/SMEAR/

下一个命令是a在最后一行 ( $) 之后追加该行SMEAR=-5。要.附加的文本结束。

x命令保存更改并退出。

每个命令都以换行符结束,使用printf '%s\n'将它们发送到ex


另请参阅这个非常相似的解决方案这是我不久前在 vi/Vim 堆栈交换中写的。


要通过将更改的文件打印到命令行而不保存更改来测试更改,请将 替换为如下x两个命令:%p 'q!'

printf '%s\n' 'g/SMEAR/d' '$a' 'SMEAR=-5' . %p 'q!' | ex file.txt

%意思是“整个缓冲区”,这就是被p打印的内容。

q!意思是“退出,放弃改变”。

将更改保存到新的文件,将其替换%pw newfile.txt

printf '%s\n' 'g/SMEAR/d' '$a' 'SMEAR=-5' . 'w newfile.txt' 'q!' | ex file.txt

w会将修改后的缓冲区写入newfile.txt.

或者,您可以在开始时执行此操作,进行备份,然后将更改的文件内容保存到原始位置,file.txt如下所示:

printf '%s\n' 'w file.txt.bak' 'g/SMEAR/d' '$a' 'SMEAR=-5' . x | ex file.txt

编辑:实际上你不需要使用q!;只需省略x就足以避免保存更改。当ex尝试读取更多输入时收到 EOF 时,它将退出,并且不会保存更改。

答案2

您可以这样尝试:如果一行匹配,只需将其复制到h旧空间,然后s替换该值。
在纬度$线上x更改保持空间和模式空间,然后检查后者是否为空。如果它不为空,则意味着替换已经完成,因此无需执行任何操作。如果它为空,则意味着未找到匹配项,因此将模式空间替换为SMEAR=-5然后追加到保持缓冲区中的当前行。最后,ex再次更改:

sed '/SMEAR/{h;s/.*/SMEAR=-5/};${x;/^$/{s//SMEAR=-5/;H};x}' infile

以上是gnu sed语法。便携的:

sed '/SMEAR/{
h
s/.*/SMEAR=-5/
}
${
x
/^$/{
s//SMEAR=-5/
H
}
x
}' infile

替代方法ed

ed -s infile<<\IN || printf %s\\n SMEAR=-5 >> infile
/SMEAR.*/s//SMEAR=-5/ 
w
q
IN

如果没有行与模式匹配,ed则会出错,因此printf...将执行第二个命令 ( ) 将该行附加到文件中。否则ed将就地编辑文件。


如果您将值SMEAR保存在变量中,例如

var=-7

你会运行:

sed '/SMEAR/{h;s/.*/SMEAR='"$var"'/};${x;/^$/{s//SMEAR='"$var"'/;H};x}' infile

或者

ed -s infile<<IN || printf %s\\n "SMEAR=${var}" >> infile
/SMEAR.*/s//SMEAR=${var}/ 
w
q
IN

答案3

或者,实施通配符的想法 (删除包含 的任何/所有现有行SMEAR,然后插入所需的行)使用石器时代工具:

(grep -v '^SMEAR=' file1; echo 'SMEAR=-5') > file1.tmp  &&  cp file1.tmp file1  &&  rm file1.tmp

或者,如果您不关心保留 的属性(例如权限)和硬链接file1,您可以这样做

(grep -v '^SMEAR=' file1; echo 'SMEAR=-5') > file1.tmp  &&  mv file1.tmp file1

或者,如果你有sponge,你可以这样做

(grep -v '^SMEAR=' file1; echo 'SMEAR=-5') | sponge file1

相关内容