Bash シェル スクリプト: apt-get update が失敗しても終了ステータスが 0 なので、終了ステータスを利用した自動更新スクリプトの作成

Bash シェル スクリプト: 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

aptエラーが発生した場合でも またはが0 を返す理由を理解するにはapt-get、まずこれらのコマンドもプログラマーによって開発されたプログラムであることを知っておく必要があります。したがって、ターミナルに返される値もプログラムの開発者によって決定されます。

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スクリプトに関する提案

コマンドが正常に実行されなかった場合に 10 回実行を試みるループを使用していることがわかりましたapt update。正直に言うと、1 回目に機能しなかった場合は、次の 9 回も機能しません。したがって、ループを作成しても意味がありません。

ここで、エラーをチェックしたい場合は、ネストされた if-else 条件を使用します。最初のレベルでステータス コードをチェックし、apt2 番目のレベルでの実行でエラーをチェックするには (つまり、終了コードが "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 に追加することもできます。

関連情報