07 settembre, 2019
Gestire condizioni di errore
Forse è solo una cosa per noi vecchi, i giovani sono abituati a un ambiente integrato, guidato, dove questi errori non possono capitare. A meno che... Ecco parlo (solo un cenno) di quando un'elaborazione è composta di più programmi concatenati da eseguire in sequenza. E (giustamente) si automatizza.
Tento di farla semplice, la realtà può essere molto più articolata, i dati possono arrivare dal web e certe valutazioni temporizzate o quando si supera una soglia predefinita o altre condizioni ancora. Tutte cose che salto, mi concentro solo su un argomento semplicissimo: l'exit-code che ogni programma ritorna (o dovrebbe tornare).
Un esempio --il minimo che sono riuscito a pensare-- è eec.py, legge dati e qui può insorgere un errore e li elabora dove non tutto può essere come previsto:
#!/usr/bin/python3
from sys import argv
def leggi_input():
global n1, n2
try:
n1 = int(argv[1])
n2 = int(argv[2])
except:
print('Errore di input')
exit(1)
def rapporto():
global n1, n2
print(n1, n2)
try:
return n1 / n2
except:
print('Errore nel rapporto')
exit(1)
# main
leggi_input()
r = rapporto()
print(n1, n2, r)
Provandolo si ha:
$ py3 eec.py 10 3
10 3
10 3 3.3333333333333335
$ py3 eec.py 10
Errore di input
$ py3 eec.py 10 0
10 0
Errore nel rapporto
OK, in caso di errore exit interrompe l'esecuzione e setta l'exit code a 1. Se tutto va come previsto il codice ritornato è 0, a essere davvero puntiglioso occorrerebbe inserire come ultima istruzione exit(0), come si fa con il C, ma Python lo fa automaticamente:
Help on built-in function exit in module sys:
exit(...)
exit([status])
Exit the interpreter by raising SystemExit(status).
If the status is omitted or None, it defaults to zero (i.e., success).
If the status is an integer, it will be used as the system exit status.
If it is another kind of object, it will be printed and the system
exit status will be one (i.e., failure).
Una cosa che non sono riuscito a trovare è la differenza tra le due diverse funzioni exit() di Python: c'è quella predefinita, usata nell'esempio, un'altra nel modulo sys. L'help riportato sopra è quello ottenuto con help(sys.exit) ma vale anche per l'exit() predefinito.
Nota: se status è una stringa il codice di uscita è sempre 1, (file ecs.py):
#!/bin/bash
from sys import argv
ec = argv[1]
print('Esco con:', ec)
exit(ec)
ottengo:
$ py3 ecs.py 0
Esco con: 0
0
$ echo $?
1
$ py3 ecs.py 10
Esco con: 10
10
$ echo $?
1
$ py3 ecs.py orrore!
Esco con: orrore!
orrore!
$ echo $?
1
OK, resta da vedere il lato bash (o altro equivalente). La versione naïf non funziona (tec.sh):
#!/bin/bash
python3 eec.py $1
echo "exit code =" $?
echo "e adesso continuo..."
$ bash tec.sh 10 3
10 3
10 3 3.3333333333333335
exit code = 0
e adesso continuo...
$ bash tec.sh 10
Errore di input
exit code = 1
e adesso continuo...
$ bash tec.sh 10 0
10 0
Errore nel rapporto
exit code = 1
e adesso continuo...
La correzione richiesta è semplice (tecs.sh):
#!/bin/bash
set -e
python3 eec.py $1 $2
echo "exit code =" $?
echo "e adesso continuo..."
$ bash tecs.sh 10 3
10 3
10 3 3.3333333333333335
exit code = 0
e adesso continuo...
$ bash tecs.sh 10
Errore di input
$ bash tecs.sh 10 0
10 0
Errore nel rapporto
OK 🤩👌
C'è ancora un altro caso che finora non abbiamo risolto: la pipe, vero che c'è pipefail e PIPESTATUS ma, nonostante le googlate, niente finora 👿
🔴
Iscriviti a:
Commenti sul post (Atom)
Nessun commento:
Posta un commento