Estou tentando escrever um script de atualização e atualização automática.
Quero utilizar o status de saída da execução do comando,
mas mesmo que o comando apt-get update falhe, ele retornará o status de saída 0.
Portanto, meu script não consegue atingir o propósito.
PERGUNTAS ===========
Por que o apt-get update retorna 0, quero obter outros números em vez de 0 quando o comando falha?
E para que meu script atinja o objetivo, como posso modificá-lo?
=====================
Obrigado pela sua leitura!
Aqui está a parte de atualização do meu script;
#!/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
Responder1
Para entender por que apt
or apt-get
retorna 0, mesmo quando você encontra um erro, primeiro você deve saber que esses comandos também são um programa desenvolvido por algum programador. Assim, os valores retornados ao terminal também são decididos pelo desenvolvedor do programa.
O único caso em que não vi apt
funcionar é quando ele é executado sem. sudo
Aqui está um trecho quando o apt é executado sem privilégio de superusuário:
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
Como você pode ver que o código de saída não é 0. Portanto, podemos concluir que o comando ou programa não foi executado.
Vejamos outro caso, quando não há conexão com a internet:
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
Como você pode ver, o código de saída é 0, embora tenhamos encontrado um erro. A razão para isso é que o programa ou comando foi executado com êxito. No entanto, não foi possível atualizar as listas de pacotes para atualizações de pacotes que precisam de atualização.
A única explicação para isso é que o desenvolvedor do apt
comando não considerou a falha na atualização da lista de pacotes como um erro para interromper o comando em si e retornar um código de status de saída de erro. Em vez disso, o comando fornece avisos após a execução.
Para entender melhor vou dar um exemplo de programa 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;
}
Saída:
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
Como você pode ver, existem 2 códigos de status de saída diferentes, porque como programador considerei que o comando executado sem nenhum argumento é um erro e deve ser finalizado com o código de saída "1". (eu poderia escolher qualquer valor). E se o comando for executado com sucesso, retornei "0" como código de status de saída, o que significa que nenhum erro foi encontrado.
Vamos dar outro exemplo:
#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;
}
Saída:
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
Novamente o mesmo programa, mas desta vez o programador (ou seja, eu) não considerou encerrar o programa com um código de status de saída diferente. Portanto, mesmo que o terminal imprima uma saída Error, o código de status de saída é "0".
Conclusão
Cabe ao desenvolvedor do programa qual valor retornar (ou seja, código de status de saída) dependendo da situação.Espero que isso esclareça o conceito de código de status de saída.
Sugestão no seu script bash
Vi que você está usando um loop que tentará executar apt update
o comando 10 vezes se não for executado com sucesso. Para ser honesto, se não funcionou na primeira vez, não funcionará nas próximas 9 vezes também. Portanto, criar um loop é simplesmente inútil.
Agora, se você quiser verificar se há um erro, use condições if-else aninhadas. Você pode verificar o código de status no primeiro nível e para verificar se há erros na execução do apt
segundo nível (ou seja, com o código de saída "0"), você pode usar algo como:
sudo apt update | grep "Err"
se grep
foi possível buscar uma linha, armazene-a como um erro em seu arquivo de log, caso contrário, a atualização foi bem-sucedida.
Responder2
Por que o apt-get update retorna 0, quero obter outros números em vez de 0 quando o comando falha?
O apt considera erros transitórios de rede como avisos (não erros) que não causam um código de saída diferente de zero. Vereste código fonte.
E para que meu script atinja o objetivo, como posso modificá-lo?
No código-fonte vinculado acima, você notará outra cláusula na condicional ( errorMode != ErrorMode::Any
). Para tratar avisos como erros, tente:
# apt -o 'APT::Update::Error-Mode=any' update
Isso fará com que o apt trate os avisos como erros. Erros transitórios de rede farão com que o apt saia diferente de zero.
Você pode adicionar isso ao apt conf, se desejar.