Bash : comment récupérer directement le code d'erreur d'une commande pour le mettre dans une condition

Bonjour à tous,

j’ai cette commande pour scanner les réseaux wifi :

# iw dev wlo1 scan

Je sais que pour avoir le code d’erreur d’une commande, il faut utiliser la variable $?

Le problème, est que je souhaite exécuter plusieurs fois cette commande iw dev wlo1 scan (en utilisant une boucle while) tant que son code d’erreur est supérieur à 0, comme ceci :

while [[ `iw dev wlo1 scan` -gt 0 ]]
do
  sleep 1
done

mais dans la condition du while, je sais que mettre iw dev wlo1 scan -gt 0 est faux, car ce que je veux c’est avoir le code d’erreur de la commande iw dev wlo1 scan dans la condition du while.

Une idée ? Merci d’avance

au hasard si tu teste juste après l’execution :

$?

Sinon tu peux aussi faire ça pour récupérer le résultat d’une commande :

resultat=$(command)
echo "$resultat"

C’est plutôt le code de sortie, en fait. Généralement si c’est 0 ça signifie que la commande s’est exécutée sans erreur, et si c’est 1 il y a eu une erreur. Mais selon les commandes, les codes de sortie peuvent avoir des significations différentes (je ne sais pas s’il existe un genre de standard).

Il veut le code de sortie, pas le résultat au sens de la sortie générée.

En fait, dans une boucle while, bash teste à chaque itération si la condition est vérifiée. Et une commande exécutée sans erreur est une condition valide.
Tu peux donc faire

while iw dev wlo1 scan ; do
    sleep 1
done

Tant que iw dev wlo1 scan sera vraie (c’est-à-dire avec un code de sortie égal à 0), les instructions dans la boucle seront exécutées. Si à une itération le code de sortie est différent de 0, la condition ne sera plus vraie et la boucle sera interrompue.

EDIT: j’ai lu un peu vite, si tu veux que les instructions dans la boucle soient exécutées lorsque la commande iw dev wlo1 scansort avec erreur, tu peux faire:

while ! iw dev wlo1 scan ; do
    sleep 1
done
1 J'aime

C’est tout à fait ça.

En Python, un entier valant 0 serait converti en booléen valant False. Et un entier de toute autre valeur serait converti en True. C’est l’exact inverse avec Bash.

Par exemple :

$ false; echo $?
1
$ true; echo $?
0

En fait, c’est plutôt les tests que l’on peut écrire en utilisant les crochets simples ou doubles qui fonctionnent en renvoyant des codes d’état. Exemples :

$ [ -a .bashrc ]; echo $?
0
$ [[ -a .bashrc ]]; echo $?
0

ou encore

$ test -a .bashrc; echo $?
0


AnonymousCoward

Bonjour,
@fluo , pourquoi veut tu faiore durer pour avoir le code d’erreur?
Car à partir du moment ou la commande est executé et la main rendu à l’environnement, le code d’erreur est généré.

1 J'aime

Merci pour tous les éléments de réponses, effectivement, on peut faire :

while ! iw dev wlo1 scan 2> /dev/null
do 
	sleep 1
	echo "Scan en cours..."
done

La raison de ce code est qu’il fait suite à ces commandes :

ip link set wlo1 down
iw dev wlo1 set type managed
ip link set wlo1 up

Et donc si toute suite après la commande ip link set wlo1 up, je lance la commande iw dev wlo1 scan, j’aurais cette erreur :

command failed: Device or resource busy (-16)

, parce que l’interface wlo1 met du temps pour être en état « up ».

J’aurais pu faire un simple sleep comme ceci :

sleep 3
iw dev wlo1 scan

, mais si un sleep de 3 secondes n’est pas suffisant pour que wlo1 soit à « up », il faudrait mettre un sleep à 4 secondes, ou à 5 secondes.

Mais pour ne pas à définir en dur la durée du sleep, je préfère utiliser une boucle while pour vérifier si wlo1 est prêt pour le scan, donc « tant » que wlo1 n’est « pas encore » prêt pour le scan, càd si la commande iw dev wlo1 scan 2> /dev/null retourne false, alors on revérifie à nouveau cette condition 1 seconde plus tard , sinon si ça ne retourne pas false, c’est que wlo1 est prêt pour le scan, et donc va scanner et on sort donc de la boucle while.

Sinon, si on veut en plus faire un egrep pour filtrer la sortie en cas de succès :

while true
do 
	#On exécute la commande :
	if ! iw dev wlo1 scan 2> /dev/null | egrep "BSS ([a-zA-Z0-9]{2}:)|SSID|freq|rates|signal|primary channel|WPA|RSN" 
	
	#Et donc si elle retourne une erreur, on passe à la prochaine itération de la boucle while :
	then
		sleep 1
		echo "Scan en cours..."
	else
		#Alors la commande sera exécuté sans erreur, et donc on sort de la boucle while :
		break
	fi	
	
done
ip link set wlo1 down && iw dev wlo1 set type managed && ip link set wlo1 up

Ainsi il ne fait la commande suivante que si le retour de la commande précédente est true.

Merci pour ta réponse

j’ai testé :

ip link set wlo1 down && iw dev wlo1 set type managed && ip link set wlo1 up && iw dev wlo1 scan && echo "scan réussi"

ça me retourne :

command failed: Device or resource busy (-16)

je pense que c’est parce que « && » n’est pas asynchrone, càd « n’attend » pas que iw dev wlo1 scan retourne true pour pouvoir exécuter echo « scan réussi »

peut être alors:

ip link set wlo1 down && wait $! && iw dev wlo1 set type managed  && wait $! && ip link set wlo1 up

$! est le numéro de process de la commande précédente il me semble.
mais je ne sais pas si ca fonctionne.
Ou bien sous la forme:

ip link set wlo1 down
wait $!
iw dev wlo1 set type managed
wait $!
ip link set wlo1 up