我正在尝试编写自动更新和升级脚本。
我想利用命令执行的退出状态,
但即使 apt-get update 命令失败,它也会返回退出状态 0。
所以我的脚本无法达到目的。
问题============
为什么 apt-get update 返回 0,但是当命令失败时我想获取其他数字而不是 0?
为了使我的脚本达到目的,我该如何修改它?
=====================
感谢您的阅读!
这是我的脚本的更新部分;
#!/bin/bash -x
### Variables
count=
command_result=""
### Main
echo "$(LC_TIME=en_US.UTF-8 date)" >> log_update
until [ "$count" = "10" ] || [ "$command_result" = "done" ]; do
sudo apt-get update
if [ "$?" = "0" ]; then
echo "Update succeeds." >> ~/log_update
command_result="done"
fi
count=$((count + 1))
done
if [ "$command" != "done" ]; then
echo "Time Out: Update FAILED! Solve Problem." >> log_update
fi
答案1
要理解为什么apt
或apt-get
即使在遇到错误时也返回 0,您首先应该知道这些命令也是由某个程序员开发的程序。因此返回到终端的值也是由程序的开发人员决定的。
我看到的唯一apt
不起作用的情况是在没有超级用户权限的情况下执行sudo
。这是在没有超级用户权限的情况下执行 apt 时的代码片段:
mars@HP-Notebook:~/Desktop/Practice/cpp$ apt update
Reading package lists... Done
E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
E: Unable to lock directory /var/lib/apt/lists/
W: Problem unlinking the file /var/cache/apt/pkgcache.bin - RemoveCaches (13: Permission denied)
W: Problem unlinking the file /var/cache/apt/srcpkgcache.bin - RemoveCaches (13: Permission denied)
mars@HP-Notebook:~/Desktop/Practice/cpp$ echo $?
100
如您所见,退出代码不为 0。因此我们可以得出结论,命令或程序未执行。
让我们再看另一种情况,即没有互联网连接时:
mars@HP-Notebook:~/Desktop/Practice/cpp$ sudo apt update
Err:1 http://security.ubuntu.com/ubuntu bionic-security InRelease
Could not resolve 'security.ubuntu.com'
Err:2 http://dl.google.com/linux/chrome/deb stable InRelease
Could not resolve 'dl.google.com'
Err:3 http://in.archive.ubuntu.com/ubuntu bionic InRelease
Could not resolve 'in.archive.ubuntu.com'
Err:4 https://download.sublimetext.com apt/stable/ InRelease
Could not resolve 'download.sublimetext.com'
Err:5 http://in.archive.ubuntu.com/ubuntu bionic-updates InRelease
Could not resolve 'in.archive.ubuntu.com'
Err:6 http://in.archive.ubuntu.com/ubuntu bionic-backports InRelease
Could not resolve 'in.archive.ubuntu.com'
Reading package lists... Done
Building dependency tree
Reading state information... Done
All packages are up to date.
W: Failed to fetch http://in.archive.ubuntu.com/ubuntu/dists/bionic/InRelease Could not resolve 'in.archive.ubuntu.com'
W: Failed to fetch http://in.archive.ubuntu.com/ubuntu/dists/bionic-updates/InRelease Could not resolve 'in.archive.ubuntu.com'
W: Failed to fetch http://in.archive.ubuntu.com/ubuntu/dists/bionic-backports/InRelease Could not resolve 'in.archive.ubuntu.com'
W: Failed to fetch http://security.ubuntu.com/ubuntu/dists/bionic-security/InRelease Could not resolve 'security.ubuntu.com'
W: Failed to fetch https://download.sublimetext.com/apt/stable/InRelease Could not resolve 'download.sublimetext.com'
W: Failed to fetch http://dl.google.com/linux/chrome/deb/dists/stable/InRelease Could not resolve 'dl.google.com'
W: Some index files failed to download. They have been ignored, or old ones used instead.
mars@HP-Notebook:~/Desktop/Practice/cpp$ echo $?
0
如您所见,即使我们遇到了错误,退出代码也为 0。原因是程序或命令确实成功执行。但是,它无法更新需要升级的软件包的升级包列表。
对此唯一的解释是,apt
命令的开发人员没有将更新软件包列表失败视为错误,从而停止命令本身并返回错误退出状态代码。相反,该命令在执行后提供警告。
为了更好地理解,我将举一个 C 程序的例子:
#include<stdio.h>
int main(int argc, char *argv[]) {
if(argc==2)
printf("Welcome Master %s\n", argv[1]);
else {
fprintf(stderr, "Usage : %s <name>\n", argv[0]);
return 1;
}
return 0;
}
输出:
mars@HP-Notebook:~/Desktop/Practice/cpp$ ./batman
Usage : ./batman <name>
mars@HP-Notebook:~/Desktop/Practice/cpp$ echo $?
1
mars@HP-Notebook:~/Desktop/Practice/cpp$ ./batman Bruce
Welcome Master Bruce
mars@HP-Notebook:~/Desktop/Practice/cpp$ echo $?
0
如您所见,有 2 个不同的退出状态代码,因为作为一名程序员,我认为不带参数执行的命令是错误的,应该以退出代码“1”终止。(我可以选择任何值)。如果命令执行成功,我返回“0”作为退出状态代码,表示没有遇到错误。
让我们再举一个例子:
#include<stdio.h>
int main(int argc, char *argv[]) {
if(argc==2)
printf("Welcome Master %s\n", argv[1]);
else
printf("ERROR!!\nUsage : %s <name>\n", argv[0]);
return 0;
}
输出:
mars@HP-Notebook:~/Desktop/Practice/cpp$ ./batman_error
ERROR!!
Usage : ./batman_error <name>
mars@HP-Notebook:~/Desktop/Practice/cpp$ echo $?
0
mars@HP-Notebook:~/Desktop/Practice/cpp$ ./batman_error Bruce
Welcome Master Bruce
mars@HP-Notebook:~/Desktop/Practice/cpp$ echo $?
0
再次运行相同的程序,但这次程序员(即我)没有考虑使用不同的退出状态代码来终止程序。因此,即使终端打印了“Error”的输出,退出状态代码也是“0”。
结论
返回哪个值(即退出状态代码)取决于程序开发人员,具体取决于具体情况。我希望这能澄清退出状态代码的概念。
对你的 bash 脚本的建议
我看到你使用了一个循环,apt update
如果命令执行不成功,它将尝试执行 10 次。老实说,如果第一次不成功,那么接下来的 9 次也不会成功。因此创建循环毫无意义。
现在,如果您想检查错误,请使用嵌套的 if-else 条件。您可以在第一级检查状态代码,并在apt
第二级检查执行错误(即退出代码为“0”),您可以使用类似以下内容:
sudo apt update | grep "Err"
如果grep
能够获取一行,则将其作为错误存储在日志文件中,否则更新成功。
答案2
为什么 apt-get update 返回 0,但是当命令失败时我想获取其他数字而不是 0?
apt 将瞬时网络错误视为警告(而非错误),不会导致非零退出代码。请参阅此源代码。
为了使我的脚本达到目的,我该如何修改它?
在上面链接的源代码中,您会注意到条件 ( errorMode != ErrorMode::Any
) 中的另一个子句。要将警告视为错误,请尝试:
# apt -o 'APT::Update::Error-Mode=any' update
这将导致 apt 将警告视为错误。瞬态网络错误将导致 apt 以非零值退出。
如果需要的话,您可以将其添加到 apt conf。