如果不匹配,如何在sed中添加一行

Evi*_*ine 40 bash sed

我使用以下sed命令替换配置文件中的一些参数:

sed -i 's/^option.*/option=value/g' /etc/fdm_monitor.conf
Run Code Online (Sandbox Code Playgroud)

现在我有一个问题.如果该行不存在,我想将其添加到文件的底部.

我用popen一个C程序来调用它.我试过用awk.

kev*_*kev 73

试试这个:

grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file
Run Code Online (Sandbox Code Playgroud)

  • 有关说明,请参见:[explainshell](https://explainshell.com/explain?cmd=grep+-q+%27%5Eoption%27+file+%26%26+sed+-i+%27s%2F%5Eoption.*%2Foption %3Dvalue%2F%27 + file +%7C%7C + echo +%27option%3Dvalue%27 +%3E%3E + file) (3认同)

Mar*_*lin 14

使用sed,简单的语法:

sed \
    -e '/^\(option=\).*/{s//\1value/;:a;n;ba;q}' \
    -e '$aoption=value' filename
Run Code Online (Sandbox Code Playgroud)

这将替换参数(如果存在),否则将其添加到文件的底部.

-i如果要就地编辑文件,请使用该选项.


如果你想接受并保留空格,除了删除评论,如果该行已经存在,但已被注释掉,请写:

sed -i \
    -e '/^#\?\(\s*option\s*=\s*\).*/{s//\1value/;:a;n;ba;q}' \
    -e '$aoption=value' filename
Run Code Online (Sandbox Code Playgroud)

请注意,选项和值都不能包含斜杠/,否则您必须将其转义为\/.


要使用bash变量$option$value,你可以写:

sed -i \
    -e '/^#\?\(\s*'${option//\//\\/}'\s*=\s*\).*/{s//\1'${value//\//\\/}'/;:a;n;ba;q}' \
    -e '$a'${option//\//\\/}'='${value//\//\\/} filename
Run Code Online (Sandbox Code Playgroud)

bash表达式${option//\//\\/}引用斜杠,它将全部替换/\/.

注意:我刚陷入困境.在bash中你可以引用"${option//\//\\/}",但是在busybox中,这不起作用,所以你应该避免引号,至少在非bourne-shell中.


全部结合在一个bash函数中:

# call option with parameters: $1=name $2=value $3=file
function option() {
    name=${1//\//\\/}
    value=${2//\//\\/}
    sed -i \
        -e '/^#\?\(\s*'"${name}"'\s*=\s*\).*/{s//\1'"${value}"'/;:a;n;ba;q}' \
        -e '$a'"${name}"'='"${value}" $3
}
Run Code Online (Sandbox Code Playgroud)

说明:

  • /^\(option=\).*/:匹配以option=和(.*)开头的行忽略后的所有内容=.该\(... \)围住我们会重用部分\1之后.
  • /^#\?(\\*'"${option//////}"'\*=\ s*).*/:忽略在行首处注释掉的代码#.\?意思是"可选的".评论将被删除,因为它在\(... 之外的复制部分之外\).\s*意味着"任意数量的空白区域"(空间,制表机构).复制空格,因为它们在\(... 内\),因此您不会丢失格式.
  • /^\(option=\).*/{…}:如果匹配一行/…/,则执行下一个命令.要执行的命令不是单个命令,而是块{…}.
  • s//…/:搜索和替换.由于搜索词为空//,因此它适用于最后一场比赛/^\(option=\).*/.
  • s//\1value/: Replace the last match with everything in(...), referenced by\ 1值and the text`
  • :a;n;ba;q:设置标签a,然后读取下一行n,然后分支b(或转到)回到标签a,这意味着:读取文件的所有行,所以在第一次匹配后,只需获取所有后续行而无需进一步处理.然后qguit因此忽略其他一切.
  • $aoption=value:在文件末尾$,附加a文本option=value

有关更多信息sed和命令概述,请访问我的博客:

  • 值得一提的是,文件“filename”或“$3”不能为空 (2认同)

ste*_*pse 5

作为仅awk的单行代码:

awk -v s=option=value '/^option=/{$0=s;f=1} {a[++n]=$0} END{if(!f)a[++n]=s;for(i=1;i<=n;i++)print a[i]>ARGV[1]}' file
Run Code Online (Sandbox Code Playgroud)

ARGV [1]是您的输入fileforEND块循环中将其打开并写入。fileEND块中打开输出以替换对实用程序的需求,例如sponge或写入临时文件,然后mv将临时文件写入file

数组的两个分配将a[]所有输出线累加到中aif(!f)a[++n]=s追加新option=value,如果主要的awk循环找不到optionfile

为了增加可读性,我添加了一些空格(但不是很多),但是在整个awk程序中,您实际上只需要一个空格,后面是一个空格print。如果file包含,# comments它们将被保留。