我有点进退两难。尽可能简单地说,我正在尝试编写一个脚本的一部分,该脚本将利用 sed 在 Linux 中编辑 /etc/sudoers 文件。由于我使用的帐户,我需要使用 sudo 运行 sed 命令来进行此编辑。然而,由于这个原因,在对文件进行所有编辑之前我无法结束命令,否则我将把自己锁在外面。
我特别尝试修改 /etc/sudoers 文件中的 %wheel 组,并且各个服务器上的文件中存在预先存在的条目。我想添加我自己的优化条目,注释掉旧条目,最后确保我刚刚添加的条目没有被注释掉。
我在 sed 中编写了语句来执行此操作,并且它们单独运行得很好,当我尝试做任何事情以允许同一命令中的多个语句时,这两个语句都不起作用。 (即使我没有收到任何语法错误)
例如我的陈述:
sudo sed 's/.*wheel/#&/' /etc/sudoers
---- 本身效果很好
sudo sed 's/^#\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\)/\1/' /etc/sudoers
---- 本身也很好用
但是,由于我必须将它们组合成一个命令,那么事情就会停止工作......例如:
sudo sed 's/(.*wheel/#&) (^#\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\))/' /etc/sudoers -
---不,没有骰子
或者
sudo sed -e 's/.*wheel/#&/' -e 's/^#\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\)/\1/' /etc/sudoers
---- 也不起作用
等等,似乎没有什么可以解决这个问题。运行上述 2 个命令后的输出显示它没有变化,就像我刚刚在原始文件上运行了 cat 一样。 (是的,我知道我不会在第二次永久编辑该文件)
现在我明白了,是的......我可以在文件底部添加一个临时条目供我的用户开始,然后将其删除作为最后一步来规避此问题。或者,我可以使用循环运行脚本,并且也可能成功,但必须有一种更优雅的方法来按照我的预期使用单个命令来完成此操作。
有人有主意吗?另外,如果有更好的方法来完成我最初打算做的事情,我很想知道。
编辑:输入/输出示例:
默认情况下文件中的行:
%wheel ALL=(ALL) ALL
%wheel ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL ---added by me in a previous step
#%wheel ALL=(ALL) NOPASSWD: ALL
我希望 sed 运行后的最终产品如下所示:
#%wheel ALL=(ALL) ALL
%wheel ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL
#%wheel ALL=(ALL) NOPASSWD: ALL
我不希望它看起来像这样:
#%wheel ALL=(ALL) ALL
#%wheel ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL
#%wheel ALL=(ALL) NOPASSWD: ALL
和我不希望它看起来像这样:
%wheel ALL=(ALL) ALL
%wheel ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL
%wheel ALL=(ALL) NOPASSWD: ALL
就像现在一样,多语句 sed 命令似乎没有执行任何操作,只有当我将它们作为单独的命令执行时,我才能获得所需的输出。 (在这种情况下我不能这样做)
任何帮助,将不胜感激!
答案1
将示例添加到原始问题后的最终编辑:
使用 Debian Jessie / sed (GNU sed) 4.2.2,您的第二个带有两个“-e”表达式的 sed 命令在提供的示例输入上对我来说可以正常工作。 (大多数情况下。最后一行以 2 个注释字符结尾,但这不应该是一个主要问题。)不确定不同版本的sed
处理多个表达式的方式是否存在一些差异?
这不是我首选的解决方案,但如果您无法让 sed 对多个表达式进行可预测的行为,您也可以tee
在单个 sed 命令管道的末尾使用。
sudo cat /etc/sudoers | { multiple sed commands in pipeline } | sudo tee /etc/sudoers
在评论中进行一些澄清后首次编辑:
如果您要添加的行在 sed 运行之前被注释掉,则第一个正则表达式将向其中添加第二个注释字符。由于行首有两个“#”字符,第二条语句不再匹配并且不执行任何操作。一个简单的编辑是在第二个表达式中的“#”字符上使用 1-or-more 修饰符:
sudo sed -e 's/.*wheel/#&/' -e 's/^#\+\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\)/\1/' /etc/sudoers
原答案:
如果我没有弄错你的正则表达式,你的第二个命令是撤消第一个命令。作为一个简化的例子:
echo a | sed -e 's/a/b/' -e 's/b/a/'
将打印a
.每行按顺序执行多个表达式。
一种选择是在第一步中使用备用注释分隔符,然后添加第三步将其子出来。例如,不要在第一个表达式的行开头添加“#”,而是使用's/.*wheel/--&/'
.然后,在第二个表达式取消注释所需的行后,添加第三个表达式-e 's/^--/#/'
来清理它。
答案2
我如何理解 OP 需要标记所有行车轮作为评论(除了文本)%wheel\s\+ALL …
sudo sed '
/%wheel\s\+ALL=(ALL)\s*NOPASSWD:\s*LOG_INPUT:\s*LOG_OUTPUT:\s*ALL/{
s/^#\+\s*//
b
}
/^[^#].*wheel/s/^/#/
' /etc/sudoers