Я пытаюсь написать сценарий автоматического обновления и модернизации.
Я хочу использовать статус завершения выполнения команды,
но даже если команда 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
or 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.