插入或更新行的最简洁方法是什么?

插入或更新行的最简洁方法是什么?

我编写了很多临时脚本来向 sudoers、sysctl.conf 等添加行。通常我使用 lineinfile ansible 模块。然而,有时我无法这样做,所以我使用:

WHAT_I_WANT='my line of text = something'
WHAT_TO_REPLACE='my line of text = .*'
FILE_TO_EDIT=conf_file.conf
if ( ! grep -q "^$WHAT_I_WANT\$" FILE_TO_EDIT ); then
    echo  "$WHAT_I_WANT" >> FILE_TO_EDIT
else
    sed -i "s/$WHAT_TO_REPLACE/$WHAT_I_WANT/g' FILE_TO_EDIT
fi

我的猜测是有一种更有效的方法来做到这一点。理想情况下使用一行和一种语言(并且还以允许正则表达式匹配、删除注释掉的行和备份文件的方式)但我不知道那是什么。

答案1

  • 在我看来,使用超长变量名来替换长字符串会适得其反。
  • 要在 grep/sed 命令中扩展变量,请使用双引号。
  • .*在变量赋值中使用通配符将进行文件名扩展(通配符)
  • 以下脚本在成功&&或失败时使用条件执行||,而不是 if。

REPL='something'
PATT='my line of text = '
FILE=conf_file.conf

cat $FILE
echo '========='

grep -q "^$PATT" $FILE && (sed -i "s/^$PATT.*$/$PATT$REPL/" $FILE) || (echo "$PATT$REPL" >> $FILE)

cat $FILE

答案2

实际上不是一句简单的话,但您可以通过一次调用来完成此操作sed

sed -e '
   /pat/{s//repl/g;h;}
   $!b
   G
   s/\n..*//;t
   s/$/repl/
' yourfile

注意:我特意分别使用patrepl来表示模式和替换,而不是像您那样使用 shell 变量。基本上有两个主要原因,它们会妨碍 sed 代码流+为了正确性,我们需要引用两者,并且不同的是,才能使它们工作。那项工作我就交给你了。

流程:比如说,文件从来没有 /pat/ 然后所有行都被 $!b 命令带到 stdout,并且当用 G 附加时最后一行只是看到一个空保留,因此t不被获取,并且我们有一个附加操作。

当我们看到 /pat/ 线时,则它是 s///-ed 并标记了保留区域。如果它不是最后一行,我们只需突破到标准输出即可。对于 eof,我们对保持进行检查,并且由于它非空(假设repl是 )NONEMPTY,因此在从模式空间中删除保持后将采用测试路径。


Perl提供了与代码中逐字意图匹配的清晰度:

perl -lne '$a += s/pat/repl/g,print}{print q[repl] unless $a'

解读为:该变量$a用作替换次数的计数器。最后,当之前没有进行任何替换时,我们将追加到文件中。

至于通过变量提供模式/替换信息,我们可以这样做:

WHAT_I_WANT='my line of text = something'
WHAT_TO_REPLACE='my line of text = .*'
FILE_TO_EDIT=conf_file.conf

perl -li -sn -e '
        $a += s/$pat/$repl/g,print}{print $repl unless $a
' -- -pat="$WHAT_I_WANT" -repl="$WHAT_TO_REPLACE" -- "$FILE_TO_EDIT"

相关内容