Скрипты оболочки Bash: хотя обновление apt-get завершилось неудачей, статус выхода равен 0, написание сценариев автоматического обновления с использованием статуса выхода

Скрипты оболочки Bash: хотя обновление 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

Чтобы понять, почему aptor apt-getвозвращает 0, даже если вы столкнулись с ошибкой, вы должны сначала знать, что эти команды также являются программой, которая была разработана каким-то программистом. Следовательно, возвращаемые на терминал значения также определяются разработчиком программы.

Единственный случай, когда я видел, что apt 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.

Связанный контент