Bash Shell腳本:雖然apt-get更新失敗,但退出狀態為0,利用退出狀態編寫自動更新腳本

Bash Shell腳本:雖然apt-get更新失敗,但退出狀態為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

要理解為什麼aptorapt-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。原因是程式或指令確實執行成功。但是,它無法更新需要升級的軟體包的升級軟體包清單。

對此唯一的解釋是,aptcommand 的開發者沒有將更新包清單失敗視為錯誤來停止命令本身並傳回錯誤退出狀態代碼。相反,該命令在執行後會提供警告。

為了更好地理解,我將舉一個 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

再次是相同的程序,但這次程式設計師(即我)沒有考慮使用不同的退出狀態代碼來終止程序。因此,即使終端列印錯誤輸出,退出狀態代碼仍為「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 以非零值退出。

如果需要,您可以將其新增至 aptconf。

相關內容