如何仅在 sed 替换字符串时运行命令

如何仅在 sed 替换字符串时运行命令

我想通过命令行在 Ubuntu 中启用 multiverse 存储库。

sed -i "/^# deb.*multiverse/ s/^# //" /etc/apt/sources.list && apt-get update

该命令每次都会运行,但只有在注释掉该行时apt-get update才有必要。sed

有没有简单的方法来检测是否sed替换字符串并根据该结果运行命令?

答案1

我知道这个问题已经有了答案,但我很好奇是否可以提出一个仅 sed 的答案(不使用 grep 作为接受的答案)。事实证明,这似乎是可能的:

sed -ni '/^# deb.*multiverse/{;h;s/^# //;};p;${;g;/^#/!q1;}' /etc/apt/sources.list
  && apt-get update

(当然,所有内容都必须在同一行,但我希望所有内容都可见,而不必水平滚动。)

解释 :

  • 寻找图案 ( /^# deb.*multiverse/)
  • 如果发现:
    • 将线路保留在保留缓冲区中 ( h)
    • 取消注释 ( s/^# //)
  • 打印该行
  • 仅在最后一行 ( $)
    • 将保持缓冲区中保存的行复制到模式缓冲区 ( g)
    • 测试保持缓冲区是否以注释符号开头(如果没有发生替换,则为空)( /^#/)
    • 如果没有匹配,则退出并显示代码1以表明未进行替换 ( !q1)(否则正常退出并显示代码0

现在我知道这个答案确实不如简单地使用 grep 那么清晰,但我对这个挑战感兴趣并提出了这个,所以我想我会分享。

答案2

也许这里最简单的事情就是grep首先添加注释行:

grep -q '^# deb.*multiverse' /etc/apt/sources.list &&
  sed -i '/^# deb.*multiverse/ s/^# //' /etc/apt/sources.list &&
  apt-get update

答案3

{   sed -i '/^# \(deb.*multiv.*\)/h;s//\1/p
        $x;s//apt-get update/w /dev/fd/2' file
}   2>&1 >/dev/null | sh -v

如果该命令在读取时至少进行了一次替换,则只会输出通过管道馈送apt-get update的行。shfile

答案4

另一种方法是使用ed,利用内置功能:如果在寻址行上没有进行替换,则被视为错误;如果标准输入是常规文件, ed 应以非零退出状态终止
你可以使用此处字符串:

ed -s /etc/apt/sources.list <<< $',s/^# \\(deb.*multiverse\\)/\\1/\nw\n!apt-get update\nq'

或者特雷多克:

ed -s /etc/apt/sources.list <<IN
,s/^# \(deb.*multiverse\)/\1/
w
!apt-get update
q
IN

将以下命令传递给ed

,s/^# \(deb.*multiverse\)/\1/      replace pattern with something 
w                                  write changes to file
!apt-get update                    run this command in shell
q                                  quit editor

但是,如果没有找到匹配,则意味着没有s进行替换,因此ed会被轰炸(唯一的输出是一个问号,?表示error1),因此后续行上的子命令不会被执行。要测试它,您实际上可以替换apt-get update为另一个命令,例如cat /etc/apt/sources.listecho DONE


1:如果问号困扰您,只需重定向stderr/dev/null例如:

ed -s /etc/apt/sources.list 2>/dev/null <<....

相关内容