Contenu | Rechercher | Menus

Annonce

DVD, clés USB et t-shirts Ubuntu-fr disponibles sur la boutique En Vente Libre

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 13/01/2020, à 22:55

Plug

[Résolu] Script - Gestion des erreurs - Récupérer un Warning

Bonjour,

Le sujet semble bateau mais je me heurte à pas mal de contraintes que je n'arrive pas à contourner.

Le problème :

J'utilise une commande dans un script qui de temps en temps me renvoie un Warning

Warning: remote port forwarding failed for listen port 12345

J'aimerai donc "trapper" ce warning pour agir dans mon script.

Ce qui ne marche pas :

  • Mettre le résultat de la commande dans une variable : ça bloque la commande (s'exécute mais ne passe pas à la suite)

  • tester $? : Elle est à 0 (ce n'est qu'un Warning)

  • set -e : je ne veux pas sortir du programme

  • trap 'action' ERR : Ne détecte pas le Warning

La commande (pour les curieux) wink

ssh -i -NT -R $reverse_port:localhost:$local_port $user@$server -p $remote_port

Voilà c'est juste du Forwarding mais comme le Warning vient du serveur, je ne vois pas trop comment le récupérer. On pourrait peut-être rediriger la sortie vers un fichier mais on récupèrerait aussi la bannière du serveur (et il faudrait ensuite traiter le fichier).

Si vous avez d'autres idées, n'hésitez pas à me les suggérer.

Dernière modification par Plug (Le 14/01/2020, à 23:41)

Hors ligne

#2 Le 13/01/2020, à 23:07

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Tu peux rediriger la sortie d'erreur vers une substitution de processus contenant grep, dont la réussite déclenche une action :

cmd 2> >(grep -q 'Warning' && action)

Hors ligne

#3 Le 13/01/2020, à 23:34

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Merci kamaris.

J'avais déjà testé les redirections, notamment pour virer la bannière du serveur de mes log avec un 1>/dev/null.

Mais ça ne marchait pas.
Je pense que la redirection s'applique à la commande elle-même, alors que là c'est le serveur qui envoie sa bannière. Et a priori ça devrait être pareil pour le Warning.

Mais je vais re-tester (on ne sait jamais roll)

Hors ligne

#4 Le 14/01/2020, à 01:51

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Je pratique peu ce genre de choses, mais si je comprends bien, c'est de ta commande ssh que provient ce warning, non ?
Quand je le mets dans un moteur de recherche, en tout cas, c'est ce que ça me dit.
Et de toutes façons, si elle ne fait que faire suivre l'info, elle le fait bien sur un flux, qui à priori doit être le 2 plutôt que le 1 (y compris pour la bannière peut-être).

Hors ligne

#5 Le 14/01/2020, à 02:30

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

kamaris a écrit :

c'est de ta commande ssh que provient ce warning, non ?

Justement je n'en sais rien.

Ce qui est certain, c'est que seul le serveur peut détecter cette erreur.
Le fait que ssh sorte en zéro (success) me laisse à penser qu'il n'a rien détecté du tout et que c'est le socket ouvert par la commande qui transmet le Warning du serveur.

Maintenant, est-ce la commande qui fait "suivre l'info" ou est-ce juste une réponse réseau qui s'affiche sur la console ? ....

roll Je vais peut-être ouvrir une discussion dans la section réseau smile

En tout cas je vais (re)tester mais ce serait curieux que la bannière soit considérée comme une erreur.
Quant au Warning le doute m'habite wink Si c'était une erreur, pourquoi ne pas l'appeler Error ? 

On verra, je teste demain.

Encore merci.

Dernière modification par Plug (Le 14/01/2020, à 20:35)

Hors ligne

#6 Le 14/01/2020, à 02:39

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Le mot « erreur » (dans sortie d'erreur) signifie simplement qu'on est sur le flux 2 en fait, c'est-à-dire dans tout ce qui n'est pas le retour attendu du programme : ça peut donc être des infos, warnings, erreurs…
Quant au code retour 0 de ssh, peut-être est-ce simplement parce que tu utilises l'option -N (« Do not execute a remote command »), or selon le manuel, ssh renvoie le code retour de la commande exécutée (« ssh exits with the exit status of the remote command or with 255 if an error occurred »).
Et effectivement, un warning n'est pas une erreur (mais a bien sa place dans le flux 2, et pas dans le 1).

Hors ligne

#7 Le 14/01/2020, à 20:49

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Bravo kamaris tu as tout bon.

La bannière comme le Warning passent bien par 2.
Du coup oui la substitution de processus est particulièrement adaptée

ssh -i -NT -R $reverse_port:localhost:$local_port $user@$server -p $remote_port 2> >(grep -q 'Warning' && change_port)

Je vais quand même essayer d'enlever le -N.

En fait, suite à ton commentaire sur le code retour je me suis demandé à quoi servait cette option :

  • si on veut passer une commande on ne met pas -N

  • si on met -N c'est qu'on n'a pas l'intention se passer un commande

Du coup elle sert à quoi cette option ? big_smile
J'ai certainement du rater quelque chose wink

Je fini mes tests un peu plus tard et je poste les résultats...

Hors ligne

#8 Le 14/01/2020, à 22:06

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

L'option -N permet de ne pas exécuter de login shell sur la machine distante, ce qui serait le cas sans option -N et sans commande spécifiée : « If a command is specified, it is executed on the remote host instead of a login shell. »
Ça semble particulièrement adapté dans ton cas, toujours selon man ssh : « -N      Do not execute a remote command.  This is useful for just forwarding ports. »

Hors ligne

#9 Le 14/01/2020, à 23:40

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

lol oui en effet maintenant je me rappelle pourquoi je l'avais mise cette option -N (la sénilité me guette).

Pour les tests c'est OK, mise à part un petit problème annexe...

En interactif ça marche mais en script je suis obligé mettre la commande en arrière-plan sinon elle ne passe pas à la suite. De ce fait je ne récupère pas la variable positionnée après le && (qui doit rester dans le process détaché je suppose).

Mais bon ce n'est pas le sujet. Pour ce qui est de capter le Warning je passe en résolu.

Merci kamaris

Hors ligne

#10 Le 15/01/2020, à 01:05

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Si tu veux on peut regarder ça aussi.
En tout cas je pense pas que ce soit la peine d'ouvrir un nouveau sujet pour ça, surtout qu'apparemment ce serait une conséquence de la méthode utilisée pour traiter le warning.
Par contre si tu veux qu'on regarde, il faudrait que tu détailles un peu, car là je ne vois pas bien ce que tu veux dire : même en interactif, on ne peut pas récupérer une affectation de variable après le &&, car la substitution de processus se fait dans un sous-shell.

Hors ligne

#11 Le 15/01/2020, à 13:43

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Ok je vais pas refuser de l'aide smile

Alors en interactif, j'ai été un peu léger sur mon test. J'ai utilisé :

 2> >(if grep -q "Warning"; then echo Présent; else echo Absent; fi)

Donc forcément echo écrit bien sur la console.

En revanche, une affectation de variable reste dans son environnement. J'ai testé :

 2> >(if grep -q "Warning"; then export reverse_port=$((reverse_port+1)); fi)

Mais même avec un export je ne récupère pas ma variable modifiée.

Donc là, je n'ai plus trop d'idée...

Hors ligne

#12 Le 15/01/2020, à 15:03

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Pour ce qui est de l'interactif, on pourrait passer par une simple redirection avec un pipe et une substitution de commande :

reverse_port=$(cmd 2>&1 | grep -q 'Warning' && echo $((reverse_port+1)) || echo $reverse_port)

Ou bien, si on veut faire plus de choses en cas de warning, récupérer une valeur booléenne et agir en fonction :

warn=$(cmd 2>&1 | grep -q 'Warning' && echo 1 || echo 0)
if ((warn)); then …
else …
fi

Par contre, si la commande ssh doit vraiment s'exécuter en arrière plan, c'est autre chose.
Là je pense qu'il faudrait que tu donnes plus de détails, ou carrément ton script, pour qu'on voit mieux.

Dernière modification par kamaris (Le 15/01/2020, à 15:05)

Hors ligne

#13 Le 15/01/2020, à 20:25

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Dans mon script, si je n'utilise pas l'option -f sur la commande ssh, il reste bloqué en attente de je ne sais quoi.
En soi ce n'est pas gênant puisqu'il fait le job mais j'aimerai juste tester le code retour pour éventuellement traiter avec un

ret=$?
case ret in

Si je fais

ret=$(ssh ... 

là encore il ne rend pas la main.

En interactif, c'est un peu pareil, sauf que si je fais un retour chariot sur la console, je récupère bien le prompt.

Voilà, je ne sais pas à quoi c'est dû (je n'y ai pas encore réfléchi).

Hors ligne

#14 Le 15/01/2020, à 21:16

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

As-tu essayé l'option ExitOnForwardFailure ? Elle semble assez indiquée dans ton cas…
Après je ne peux pas trop tester ce genre de trucs à la volée, et je ne pratique pas ssh tous les jours, donc je vais avoir du mal à te répondre sur les questions spécifiques à ssh.
Si quelqu'un qui s'y connait bien dans ce domaine pouvait prendre le relais…

Hors ligne

#15 Le 15/01/2020, à 23:59

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Oui j'avais essayé mais ce n'était pas concluant (je ne me rappelle plus quel était le problème).

Finalement j'ai abandonné les tests avec cette option car sur le principe je préfère gérer l'erreur (pour éventuellement rattraper le coup) plutôt que de simplement sortir. d'où ce fil de discussion wink

Hors ligne

#16 Le 16/01/2020, à 02:25

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Eh bien sinon, tu peux essayer de passer par kill / trap.
Tu déclares d'abord ton action à exécuter en cas de warning, puis tu fais s'exécuter ta commande en arrière plan en lui faisant envoyer un signal dans ce cas :

trap 'action' RTMIN
…
script_pid=$BASHPID
cmd 2> >(grep -q 'Warning' && kill -s RTMIN $script_pid) &
…
wait
sleep 0.1

Le sleep 0.1 à la fin, c'est pour que le script existe encore lorsque le signal envoyé lui parvient, car juste avec le wait ça peut ne pas suffir sur les petits tests que j'ai faits.
Pour mettre cmd en arrière plan, dans ton cas ou ssh a elle-même une option -f de mise en arrière plan, je ne sais pas ce qui est le mieux entre cette option ou le « & » : à tester.

Hors ligne

#17 Le 16/01/2020, à 13:02

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Merci encore kamaris pour tes efforts.

Donc là je sors du script (ce que je voulais éviter).

Si j'ai bien compris ta proposition, je tue le process pour incrémenter ma variable remote_port et je relance le même script avec cette nouvelle variable ?

Il faudrait donc que je passe remote_port en paramètre d'appel de mon script...

C'est ça ?

Sinon il n'y a vraiment aucun moyen de communiquer entre processes sous linux ?
Je vais chercher encore, mais la semaine prochaine (là je pars en déplacement ce soir)

Hors ligne

#18 Le 16/01/2020, à 14:48

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Plug a écrit :

Donc là je sors du script (ce que je voulais éviter).

Si j'ai bien compris ta proposition, je tue le process pour incrémenter ma variable remote_port et je relance le même script avec cette nouvelle variable ?

Non, non, pas du tout : là encore, il ne faut pas se laisser abuser par les mots (comme pour sortie d'erreur plus haut), il faut lire les définitions, qui se trouvent dans les manuels.
Ça n'est pas parce que la commande kill s'appelle « kill » qu'elle (ne) sert (qu')à tuer smile
Elle ne tue que dans le cas particulier où le signal qu'elle envoie est KILL (signal numéro 9), mais dans le cas général, elle sert à envoyer un signal à un processus.

Plug a écrit :

Sinon il n'y a vraiment aucun moyen de communiquer entre processes sous linux ?

Eh bien si, précisément avec le couple kill - trap : kill pour l'envoi des signaux, trap pour leur réception wink
Dans le schéma décrit en #16, le process où s'exécute cmd envoie donc au process où s'éxécute le script un signal RTMIN lorsque cmd produit un warning, ce qui déclenche alors l'exécution de « action » par la commande trap.

Hors ligne

#19 Le 16/01/2020, à 15:22

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

En effet je me laisse souvent abuser par "le poids des mots" wink

Donc je boucle sur ma commande avec « action » = ((reverse_port++))
jusqu'à ce que je n'aie plus de warning.

J'ai bon cette fois ? roll

Hors ligne

#20 Le 16/01/2020, à 15:49

credenhill

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

hello

Plug a écrit :

Sinon il n'y a vraiment aucun moyen de communiquer entre processes sous linux ?

par un fichier FIFO (named pipes)

mkfifo /tmp/fifo1

une tache écrit

cmd > /tmp/fifo1

une autre tache lit

cmd < /tmp/fifo1

Hors ligne

#21 Le 16/01/2020, à 17:17

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Plug a écrit :

Donc je boucle sur ma commande avec « action » = ((reverse_port++))
jusqu'à ce que je n'aie plus de warning.

J'ai bon cette fois ? roll

Eh bien je ne sais pas trop en fait, vu que jusque-là je n'ai pas trop compris ce que fait globalement ton script… (à quoi sert ce reverse_port déjà ?)
En #1 tu disais : « J'aimerai donc "trapper" ce warning pour agir dans mon script. »
Ce que je t'ai donné en #16 correspond à ça, mais après…
Tu ne veux pas donner ton script, ou au moins un squelette, pour qu'on voit un peu mieux ?

Hors ligne

#22 Le 17/01/2020, à 19:55

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

@credenhill : Merci pour ton aide. Mais je voulais justement éviter cette méthode que je trouve un peu lourde.

Plug a écrit :

On pourrait peut-être rediriger la sortie vers un fichier mais on récupérerait aussi la bannière du serveur (et il faudrait ensuite traiter le fichier).

Maintenant si c'est la seule méthode...

@kamaris : Mon script ne fait que définir les variables et passer la commande.

Après, que fait la commande :
Elle installe sur le serveur le transfert du port $reverse_port vers le port $local_port du client.
Le tunnel ainsi définit permet au serveur de se connecter au client (reverse ssh).
Mais si le transfert de port ne peut se faire côté serveur, il envoie juste un Warning au process distant qui l'a sollicité.
La commande client se termine correctement (le ssh a bien fonctionné) mais le serveur prévient que de son côté il n'a pas pu faire ce qui lui est demandé (écouter sur le port $reverse_port).

La principale cause de cet échec est que le port demandé est déjà utilisé.
Il suffit donc de changer de port (moi j'incrémente de 1) et de repasser la commande.

Voilà, j'espère que c'est plus clair mais je pense que je vais ouvrir un autre fil de discussion à la rubrique "réseau" pour essayer de comprendre qu'est-ce que la commande attend quand elle n'est pas détachée.

Parce qu'apparemment le problème vient du fait qu'un process fils ne peut pas remonter une variable au process père (même par export - à confirmer...).

Dernière modification par Plug (Le 17/01/2020, à 23:34)

Hors ligne

#23 Le 17/01/2020, à 21:32

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

Dans ce cas-là, si tu ne fais rien d'autre que lancer la commande ssh, et que tu la relances à chaque warning, pourquoi ne pas faire simplement

while true; do
  reverse_port_bak=$reverse_port
  reverse_port=$(ssh -i -NT -o ExitOnForwardFailure -R $reverse_port:localhost:$local_port $user@$server -p $remote_port 2>&1 | grep -q 'Warning' && echo $((reverse_port+1)) || echo $reverse_port)
  ((reverse_port == reverse_port_bak)) && break
done

Comme ça, l'option ExitOnForwardFailure t'assure que ssh rendra la main en cas de warning, le reverse_port sera incrémenté, et on relance.
Tandis que si le forward port se passe bien, tu n'as pas besoin que ssh te rende la main, puisque ton script ne fait en substance rien d'autre que lancer ssh.
Quant à la condition de sortie de boucle, tu peux la changer selon tes besoins : ici on sort si ssh se termine sans warning.
Ai-je bon ? smile

Hors ligne

#24 Le 18/01/2020, à 00:03

Plug

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

lol C'est ce que je te demandais en #19 et là c'est toi qui me demande si c'est bon.

Et bien en toute logique je dirai oui. Reste à tester, mais pour l'instant je n'ai plus le PC sous la main.

Une question encore :
Pourquoi passer de

cmd 2> >(grep -q 'Warning' 

à

cmd 2>&1 | grep -q 'Warning'

Y'a une différence ?

Dernière modification par Plug (Le 18/01/2020, à 00:05)

Hors ligne

#25 Le 18/01/2020, à 00:53

kamaris

Re : [Résolu] Script - Gestion des erreurs - Récupérer un Warning

À la réflexion non, pas vraiment, les deux sont possibles en tout cas.
J'avais introduit cette formulation-là en #12, pour permettre la substitution de commande, et donc la récupération de reverse_port en sortie.
Mais en fait, on peut tout aussi bien faire

reverse_port=$(cmd 2> >(grep -q 'Warning' && echo $((reverse_port+1)) || echo $reverse_port))

Je me suis laissé abuser par le fait que le echo se trouve alors dans une substitution de processus, en me disant qu'on ne pouvait pas avoir à la fois substitution de processus et substitution de commande.
Mais on peut évidemment avoir une substitution de commande englobante comme ci-dessus, puisque la sortie standard de la substitution de processus est alors raccordée à celle de la substitution de commande.
Ceci dit, il y a quand même une différence qu'on peut mentionner : cette formulation-là est propre à bash, tandis que l'autre est standard (tu t'en rendras compte si tu prends comme interpréteur /bin/dash ou /bin/sh au lieu de /bin/bash).

Hors ligne