我想通过命令行在 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
的行。sh
file
答案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
会被轰炸(唯一的输出是一个问号,?
表示error
1),因此后续行上的子命令不会被执行。要测试它,您实际上可以替换apt-get update
为另一个命令,例如cat /etc/apt/sources.list
或echo DONE
。
1:如果问号困扰您,只需重定向stderr
到/dev/null
例如:
ed -s /etc/apt/sources.list 2>/dev/null <<....