【问题标题】:find and replace a line OR add to the end of the file查找并替换一行或添加到文件末尾
【发布时间】:2019-02-03 14:08:59
【问题描述】:

是否可以在文件中查找和替换一行,或者如果不存在则将字符串附加到末尾?

我知道我可以用它来查找和替换

sed -i -e "s/^SEARCH/LINE 1\nLINE 2/" file

我知道我可以像这样追加到文件中:

cat << EOF | tee -i file1 file2
LINE 1
LINE 2
EOF

是否有可能以某种方式将其结合起来。因此,如果/^SEARCH.*$/ 匹配,则替换它,如果不匹配,则将替换附加到文件末尾。

使用更好的输入/输出示例更新:

例如,如果我有这个输入文件testfile:

Alpha
Bravo
Charlie

假设我想查找Bravo 并将其替换为Bravo=bingo如果Bravo 不存在,则添加Bravo=bingo,预期输出为:

Alpha
Bravo=bingo
Charlie

这是因为Bravo存在于文件中,所以被替换了。

假设我想查找Delta 并将其替换为Delta=bingo如果Delta 不存在,则添加Delta=bingo,预期输出为:

Alpha
Bravo
Charlie
Delta=bingo

这是因为Delta 不在文件中,所以它被附加了。

【问题讨论】:

  • 我没有卡在sed 上。 SO/SE 不是关于做某事的最佳 方式吗?您展示的方式有效,并且对于插入多行内容特别有用,但是如果您不需要插入多行,您是说它是 最好的 方式吗?如果你是,那我就退出。我想重新打开问题的原因是,当您不需要插入多行内容时,看看是否有更好的方法。
  • 是的,这正是我要说的,因为它清晰、简单、便携、高效、健壮且易于增强。顺便说一句,我知道 SO/SE 是什么意思,并且无法通过谷歌搜索找到它的定义。
  • 您的说明文本与您的示例输出不匹配。您说您想替换 ^SEARCH=.*$ 但这与您的“Bravo”示例不符。你说你想附加Delta=bingo,但你实际上附加了Delta
  • @jhnc 哎呀。对不起,错别字。我修好了。

标签: bash sed


【解决方案1】:

替换部分与https://stackoverflow.com/a/54504046/1745001 完全相同,但这里针对此特定用例进行了简化,如果未找到,则仅通过设置标志(如果找到则在 END 打印)来完成调整未设置标志:

awk 'BEGIN{new="LINE 1\nLINE 2"} /^SEARCH/{$0=new; f=1} {print} END{if (!f) print new}' file

上面再次使用字符串进行替换,因此适用于任何字符,/^SEARCH/ 是一个正则表达式,因为您似乎没有正则表达式元字符,但如果您这样做了,您会将其更改为 index($0,"SEARCH")==1或类似的做一个字符串而不是正则表达式匹配。

【讨论】:

    【解决方案2】:

    awk 单行:

    awk 'gsub(/^SEARCH/,"LINE 1\nLINE 2"){s=1}END{if(!s)print "LINE 1\nLINE 2"}1' file
    

    如果您想就地更改,这不会就地替换:

    awk 'gsub(/^SEARCH/,"LINE 1\nLINE 2"){s=1}END{if(!s)print "LINE 1\nLINE 2"}1' file | tee file
    

    如果原始和替换包含regex字符,请记住将其转义,这比在文本不长时更改为 match/substr 方法更容易。

    【讨论】:

    • 所以这基本上是尝试进行替换,如果它有效,它会设置一个变量,如果没有,那么它会在最后打印该行?
    • @IMTheNachoMan 对。
    • @IMTheNachoMan 无论替换是否有效,这些行都会被打印出来。 s 变量用于确定最后是否追加。
    • 鉴于原始文本和替换文本中可能存在的各种字符,这将失败。这个问题需要通过字符串操作来解决,而不是正则表达式和启用反向引用的文本。
    • @EdMorton 谢谢提及。
    【解决方案3】:

    GNU sed 单行:

    sed -i 's/^SEARCH/LINE 1\nLINE 2/;ts;bt;:s;h;:t;${x;/./!{x;s/$/\nLINE 1\nLINE 2/;be};x};:e' file
    

    【讨论】:

    • 您介意解释一下它的作用吗?我无法理解/理解。
    【解决方案4】:

    不知道单个sed 命令,但您可以让sed 备份文件,然后测试差异。如果没有区别,追加到文件末尾:

    sed -i.bak -e 's/^SEARCH/LINE 1\nLINE 2/' file
    diff file file.bak > /dev/null
    if [ $? -eq 0 ]; then
        sed -i -e '$aLINE 1\nLINE 2' file
    fi
    

    【讨论】:

    • 最后的 sed 行会将 $aLINE 视为扩展为 null 的 shell 变量。始终在字符串和脚本周围使用单引号,除非您非常需要使用双引号(例如,将脚本/字符串暴露给 shell 以进行变量扩展)并完全理解其含义和后果。考虑到 SEARCH 和每个 LINE 的不同值,它会以各种方式失败,并且在文件上调用多个工具显然是一种非常低效的方法(例如,为什么第一个 sed+diff 而不是一个 grep 用于 SEARCH?)。跨度>
    • 谢谢,@EdMorton。修好了。
    猜你喜欢
    • 2022-07-22
    • 1970-01-01
    • 1970-01-01
    • 2017-10-14
    • 1970-01-01
    • 2019-08-23
    • 2014-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多