我最近开始在一家全 Linux 公司担任 IT 人员,并注意到我们所做的一些任务可以“轻松”实现自动化。今天要自动化的任务是/etc/apt/apt.config.d/50unattended-upgrades
在新电脑上安装软件和配置。我已经编写了软件安装脚本,但现在我被困在取消注释所需的无人值守升级行上。
我给你举个例子,这个:
// Automatically upgrade packages from these (origin:archive) pairs
//
// Note that in Ubuntu security updates may pull in new dependencies
// from non-security sources (e.g. chromium). By allowing the release
// pocket these get automatically pulled in.
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
// Extended Security Maintenance; doesn't necessarily exist for
// every release and this system may not have it installed, but if
// available, the policy for updates is such that unattended-upgrades
// should also install from here by default.
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
// "${distro_id}:${distro_codename}-updates";
// "${distro_id}:${distro_codename}-proposed";
// "${distro_id}:${distro_codename}-backports";
};
看起来应该是这样的:
// Automatically upgrade packages from these (origin:archive) pairs
//
// Note that in Ubuntu security updates may pull in new dependencies
// from non-security sources (e.g. chromium). By allowing the release
// pocket these get automatically pulled in.
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
// Extended Security Maintenance; doesn't necessarily exist for
// every release and this system may not have it installed, but if
// available, the policy for updates is such that unattended-upgrades
// should also install from here by default.
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
"${distro_id}:${distro_codename}-updates";
// "${distro_id}:${distro_codename}-proposed";
// "${distro_id}:${distro_codename}-backports";
};
(更新行应该取消注释)
我尝试使用 sed 来做这件事,但就是不行,可能是因为我是个菜鸟。这是我笨拙的 sed 代码,希望有人能向我解释我做错了什么!
#!/bin/bash
sudo sed -i 's@// "${distro_id}:${distro_codename}-updates"@ "${distro_id}:${distro_codename}-updates"@' /etc/apt/apt.conf.d/50unattended-upgrades
任何帮助都将不胜感激!祝您有美好的一天!
答案1
为什么不直接创建另一个/etc/apt/apt.config.d/51my-unattended-upgrades
包含以下内容的文件:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-updates";
};
选项已合并在一起。请使用 检查apt-config dump
。
此外,只需删除单个文件即可轻松删除更改。任何升级更改/etc/apt/apt.conf.d/50unattended-upgrades
都不会破坏您的更改。
如果没有必要,最好不要更改他人的配置文件。
尝试解释一下:
从 的 python 源代码中unattended-upgrade
可以看出,它不解析 中的配置文件/etc/apt/...
。相反,它使用 python-apt-api。它类似于apt-config
在 shell 中使用(您应该始终这样做,而不是读取配置文件)。
在这种特殊情况下,python-apt-api 会合并所有文件并返回一个列表Origins-Pattern
,然后unattended-upgrade
脚本会循环遍历所有文件。
我不知道有什么好的文档可以介绍这个。你能做的最好的事情就是查看源代码。
答案2
请参见Marco 的回答,这就是正确的做法®,我sed
在这里只关注和正则表达式问题。
使用正则表达式的第一条规则是“少即是多”。不要尝试匹配整行,而是使用尽可能小的正则表达式来捕获您需要捕获的内容。例如,在这里,您不关心行首的空格,因此不必费心尝试匹配它们。此外,空格的数量很可能会发生变化,您不希望因此破坏您的脚本,所以请忽略它们!
据我所知,您真正想要做的就是//
从包含字符串的任何行中删除前导-updates
。如果是这样,您所需要的就是:
sed '/-updates/{s@^\s*//@@}' /etc/apt/apt.conf.d/50unattended-upgrades
这意味着“如果此行与 匹配-updates
,则用 替换 后面的 0 个或更多前导空格字符(注释不必是行的第一个字符) ”。因此,这将删除与匹配的行中的//
前导字符。//
-updates
如您所见,这更容易编写和理解。也就是说,您的原始命令可以按预期在示例文件中运行,只是不必要地复杂和脆弱(如果添加空格,它会中断):
$ sed 's@// "${distro_id}:${distro_codename}-updates"@ "${distro_id}:${distro_codename}-updates"@' file
/ Automatically upgrade packages from these (origin:archive) pairs
//
// Note that in Ubuntu security updates may pull in new dependencies
// from non-security sources (e.g. chromium). By allowing the release
// pocket these get automatically pulled in.
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
// Extended Security Maintenance; doesn't necessarily exist for
// every release and this system may not have it installed, but if
// available, the policy for updates is such that unattended-upgrades
// should also install from here by default.
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
"${distro_id}:${distro_codename}-updates";
// "${distro_id}:${distro_codename}-proposed";
// "${distro_id}:${distro_codename}-backports";
};
最后,几点一般性观察:
- 绝不在重要文件上使用
sed -i
而不进行备份。该-i
选项允许您指定备份后缀,因此如果您运行sed -i.bak 's/a/b/' file
,则会将原始文件复制为file.bak
。因此,您应该在您的案例中执行类似操作sudo sed -i.bak ...
,这样您就可以随时撤消操作。 - 这很少是一个好主意在脚本中添加
sudo
。相反,编写脚本时不要使用sudo
,然后使用 来调用sudo
它sudo script.sh
。