Bash Shell 脚本:尽管 apt-get update 失败,但退出状态为 0,利用退出状态编写自动更新脚本

Bash Shell 脚本:尽管 apt-get update 失败,但退出状态为 0,利用退出状态编写自动更新脚本

我正在尝试编写自动更新和升级脚本。

我想利用命令执行的退出状态,

但即使 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

要理解为什么aptapt-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。

相关内容