Contenu | Rechercher | Menus

Annonce

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 16/05/2020, à 18:25

Brice Jeunieaux

[Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Bonjour / bonsoir,

souhaitant pouvoir interrompre une commande read avec la touche Échap, j'ai décidé de me tourner vers les commandes stty et trap.

Pour vous mettre dans le contexte, j'ai une fonction qui tourne en boucle, dans laquelle on demande à l'utilisateur d'entrer ce qu'il veut. Seulement, cet utilisateur doit pouvoir interrompre la commande read avec la touche Échap. Grâce à la commande stty, s'il appuie sur cette touche, un signal d'interruption est envoyé (le signal n°2, SIGINT), et la commande trap renvoie l'utilisateur dans une deuxième fonction dès qu'elle perçoit ce signal. Dans cette deuxième fonction, on affiche un message pour prévenir l'utilisateur qu'il a appuyé sur la touche Échap et après un temps d'attente, on le renvoie dans la première fonction, où il pourra encore et encore entrer au clavier ce qu'il veut. Voici mon code - assez court - pour mieux visualiser :

#!/bin/bash

resize -s 24 80
clear

fonction() {
	
	stty intr '^[' ;
	trap commandeInterrompue 2 ;
	
	read -p "Entrez la commande : " cmdUtilisateur ;
	echo -e "Vous avez tapé la commande : $cmdUtilisateur . "
	
	if [[ "$cmdUtilisateur" == "q" ]]
	then stty sane ; clear ; exit ;
	fi
	
	sleep 3 ;
	fonction ;
	
}

commandeInterrompue() {
	
	clear
	stty sane ;
	echo -e "Vous avez interrompu le programme." ;
	sleep 1
	fonction ;
	
}

fonction ;

Le souci est que l'interruption fonctionne correctement une unique fois. Après la première interruption et notre retour dans la fonction d'origine, soit la commande stty n'associe plus ma touche Échap à l'interruption, soit la commande trap ne perçoit plus ce signal ou ne me renvoie pas dans la seconde fonction.

Ma question est donc : Que se passe t-il derrière tout ça ? Comment corriger le problème ?


Merci à vous de m'avoir lu. smile

Dernière modification par Brice Jeunieaux (Le 19/05/2020, à 22:44)

Hors ligne

#2 Le 16/05/2020, à 23:00

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Ça n'est pas un problème d'assignation de la touche échap, c'est un problème uniquement lié à trap et à l'imbrication de fonctions.
Ici, on ne sort jamais de commandeInterrompue() dès lors qu'elle a été appelée, et on ne sort donc jamais non plus de trap.

À partir de là, le signal SIGINT est désactivé pour le processus courant, tandis qu'il conserve son action habituelle d'interruption pour les éventuels processus fils.
Or, ce sur quoi on bute après appel de commandeInterrompue(), c'est read, qui est une commande interne au shell (pas un sous-processus), donc lorsque l'on envoie à nouveau le signal SIGINT, il ne se passe rien.
Si au lieu de read, il y avait un sleep suffisamment long, un nouvel envoi de SIGINT l'interromprait.

Voilà un truc qui marcherait dans ce cas (je ne dis pas qu'il faut faire ça globalement, c'est juste pour remettre les choses d'aplomb sans changer l'esprit du script) :

#!/bin/bash

fonction() (
	read -p "Entrez la commande : " cmdUtilisateur
	echo -e "Vous avez tapé la commande : $cmdUtilisateur . "
	if [[ "$cmdUtilisateur" == "q" ]]; then
		clear
		return 0
	fi
	sleep 3
)

commandeInterrompue() {
	clear
	pkill -P $$
	echo -e "Vous avez interrompu le programme."
	sleep 1
}

resize -s 24 80
clear
stty intr '^['
trap 'commandeInterrompue' 2

while ! fonction; do :; done
stty sane

La définition de fonction() avec des parenthèses au lieu des accolades fait qu'elle est lancée dans un sous-shell, et donc tuable depuis le shell parent.

Dernière modification par kamaris (Le 16/05/2020, à 23:45)

Hors ligne

#3 Le 17/05/2020, à 07:47

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Bonjour / bonsoir et avant toute chose, merci beaucoup pour ton explication !

N'ayant aucune connaissance dans le domaine des processus, mon problème était comme un mur invisible que je ne pouvais identifier et me rendait confus.
J'ai beau avoir cherché longtemps sur le Web, je n'ai trouvé que deux personnes qui semblaient être dans la même situation que moi et la réponse qui leur a été apporté est qu'à priori il s'agissait d'un bug logiciel du système qui n'était pas résoluble pour le moment. Heureux de voir que finalement, mon cas est quelque chose de parfaitement "normal", on va dire. Il faudrait vraiment que j'en apprenne plus dans le domaine, cela m'embêterait d'avoir du code dans mon programme, par rapport aux processus, que je ne comprends pas, et si je ne comprends pas mon code alors je ne le maîtrise pas, et cela devient donc une faille dans l'interface chaise-clavier. tongue

BREF. Trêve de plaisanterie, mon but pour l'instant est de savoir si j'ai bien compris l'explication que tu m'as apporté.


Si j'ai bien compris :
1) le problème ne vient pas de la commande `stty`. Cette commande ne s'arrête pas de fonctionner et donc le système envoie bien, même dans ma partie buguée, le signal d'interruption. Le problème réside donc uniquement dans la commande `trap` qui, de ce que j'ai interprété, ne semble pas pouvoir être lancée plusieurs fois au sein d'un même processus.
2) Du coup, par rapport à mon manque de connaissances, qu'est-ce qu'un processus ? Quand démarre t-il et quand s'arrête t-il ?
3) La commande `trap` ne peut donc uniquement piéger des signaux que lorsqu'il n'y a plus de processus en cours qui effectue cette même commande ? Il faudrait donc arrêter (ici manuellement) le processus-mère pour pouvoir lancer la commande dans le processus-fille ?


Après, il ne faut pas hésiter à me dire si je confonds les concepts ou autre et que peut-être processus-mère et processus-fille n'ont rien à voir avec ma situation. Également, vu que je n'y connais rien, le seul truc que je pense savoir, c'est qu'à mon avis les notions de 'fonction' (la portion de code) et 'processus' sont deux notions bien distinctes.

Dernière modification par Brice Jeunieaux (Le 17/05/2020, à 07:50)

Hors ligne

#4 Le 17/05/2020, à 10:38

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

  1. Tout à fait, le signal SIGINT est bien envoyé par l'appui sur la touche échap dans ce cas.
     

  2. Un processus est une instance en cours d'exécution d'un programme, selon par exemple cette définition : http://www.linfo.org/process.html.
    Comme dit dans ce lien, il consiste en : 1) des ressources système qui lui sont allouées, 2) une plage mémoire, 3) des attributs liés à la sécurité (propriétaire, permissions), 4) un état.
    Il démarre quand il est appelé par quelque moyen (interactif ou non), et s'arrête de manière prévue en interne, ou imprévue par un facteur extérieur… difficile d'être plus précis (voir néanmoins la section The Process Life Cycle dans le lien donné).
     

  3. Je dirais simplement : oui.
    Pour s'en convaincre, voici un exemple élémentaire :

    #!/bin/bash
    
    trap '
    	echo trap 1
    	trap "echo trap 2" 2
    	while true; do
    		echo sleep 100
    		sleep 100
    	done
    ' 2
    
    echo sleep 10
    sleep 10

    Si on lance ce script et qu'on fait ^C pendant le sleep 10, le signal SIGINT envoyé est attrapé par le premier trap, qui lance l'exécution de son petit script.
    La deuxième commande trap est alors lue, puis un sleep 100 est lancé.
    Si on fait à nouveau ^C, ce sleep 100 est simplement interrompu, et un autre se lance, sans que ni echo trap 1, ni echo trap 2 ne soit exécuté.
    La seconde commande trap n'a donc aucun effet, et la première n'en a plus tant qu'on en est pas sorti : le signal SIGINT est simplement pris comme un signal d'interruption pour le sous processus en cours, à savoir sleep 100.
     

  4. Comme je l'ai souligné en fin de mon post #2, il y deux manière de définir une fonction en shell : avec des accolades ou avec des parenthèses.
    La première manière n'engendre pas un sous processus, tandis que la seconde, si.
    Là encore, un exemple élémentaire pour s'en convaincre :

    $ unset a
    $ f() { a=1; }
    $ f
    $ echo $a
    1
    $ 
    $ unset a
    $ f() (a=1)
    $ f
    $ echo $a
    
    $ 

    En bash, il existe aussi la variable d'environnement BASHPID qui permet de connaitre le PID d'un sous-shell :

    $ f() { echo $$; echo $BASHPID; }
    $ f
    3660
    3660
    $ f() (echo $$; echo $BASHPID)
    $ f
    3660
    3921
    $ 

Dernière modification par kamaris (Le 17/05/2020, à 10:45)

Hors ligne

#5 Le 17/05/2020, à 18:00

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Pour l'instant, j'ai bien réussi à tout comprendre les notions en soi de processus, PID, commandes stty et trap, etc...
J'ai également compris ce qu'il se passait derrière mon bug (grâce à tes explications et portions de code, encore merci) et comment le corriger.
CEPENDANT, c'est lorsqu'il faut rectifier mon bug avec mon code en situation réelle que cela pose problème (oui car on se doute bien que mon code que j'ai mis dans le message d'origine est ultra condensé pour simuler le fonctionnement de mon programme).

J'ai passé toute la journée à essayer de retourner mon code dans tous les sens pour essayer d'adapter le code exemple au mien, et je ne sais pas, vraiment, je bloque. Pour le coup, là, ce sont les processus de mon cerveau qui se sont fait piéger... tongue


Pour expliquer mon vrai code, grosso modo, je suis en train de développer un jeu d'aventure textuelle en semi-lignes de commandes, c'est à dire que dans l'interface principale le joueur peut appuyer sur certaines lettres pour afficher certains menus (j'ai appelé ça le "Mode Touche"), et quand il appuie sur la lettre 'c', il peut entrer des commandes telles que "tuer troll avec épée" (j'ai appelé ça le "Mode Commande"). L'interface de jeu ressemble à ça :

1589737627.png

Bref, maintenant que j'ai bien raconté ma vie, c'est surtout là où je veux en venir :
Petit 1) j'avais besoin d'aide pour m'évader, grâce à la touche Échap, de la commande read qui est réalisé dans mon fameux "Mode Commande" afin de retourner dans mon "Mode Touche". Ça techniquement c'est résolu grâce à la commande trap et la notion d'arrêt de processeur ;
Petit 2) quelque chose que je n'ai pas expliqué dans mon post #1 car l'échantillon de code que j'ai posté ne montre pas le vrai code en réalité, et peut-être que ça joue sur ma difficulté à adapter la solution à mon problème : dans mon fameux "Mode Touche", il y a un "while read -rsn1 caractere". Ce qu'il se passe, c'est que pour que l'utilisateur entre touche par touche, le "read -n1" était nécessaire. Dans ce mode, je n'ai pas besoin de piéger la touche Échap avec "trap", mais le fait qu'on se retrouve avec un deuxième read me porte à confusion et me laisse penser que cela peut m'amener sur un autre souci... hmm

Ci-dessous, mon vrai code (avec les commande echo modifiées parce qu'on s'en fiche en soi, ce n'est pas le plus important), non pas pour qu'on fasse mon boulot à ma place mais si jamais ça peut aider à comprendre la structure de mon programme, alors c'est déjà ça de gagné.

#!/bin/bash
#Version 2 de la fonctionnalité de gameplay dual-mode pour SSFD

resize -s 24 80 ;

modeCommande=0 ;
couleurTexteDefaut='\033[0m' ;

#Variables pour la désactivation du clavier###
idClavier=$(xinput list | grep 'AT Translated Set 2 keyboard' | cut -d '=' -f 2 | cut -d '[' -f 1 | cut -d ' ' -f 1) ;
idMaitre=$(xinput list | grep 'AT Translated Set 2 keyboard' | cut -d '=' -f 2 | cut -d '(' -f 2 | cut -d ')' -f 1 | cut -d ' ' -f 2) ;
###


stty intr '^[' ;
clear

##########    Fonctions de modes     ##########

#Prompt rouge = on est en mode Touche ; Prompt vert = on est en mode Commande
couleurMode() {
	
	pkill -P $$
	
	if		[[ "$modeCommande" == 0 ]] ;
	then	couleurCommande='\033[31m' ;
	else	couleurCommande='\033[32m' ;
	fi
	
}

#Cette fonction est constamment appelée dès la sortie d'un mode, pour passer à l'autre
redirectionMode() {
	
	if		[[ "$modeCommande" == 0 ]] ;
	then	touche ;
	else	commande ;
	fi
	
}

#Le mode touche n'a à priori aucun problème
touche() {
	
	tput cup 10 7 ;
	while read -rsn1 caractere
	do
    	case "$caractere" in
    		#Ce qu'il se passe si le caractère entré est la touche '1'
        	'1')
            	xinput float $idClavier ;
            	echo "Vous avez choisi l'option 1." ;
            	tput cup 10 36 ;
            	sleep 1 ;
            	affichage2 ;
            	xinput reattach $idClavier $idMaitre ;
            	redirectionMode ;;
        	
        	#Ce qu'il se passe si le caractère entré est la touche '2'
        	'2')
            	xinput float $idClavier ;
            	echo "Vous avez choisi l'option 2." ;
            	tput cup 10 36 ;
            	sleep 1 ;
            	affichage2 ;
            	xinput reattach $idClavier $idMaitre ;
            	redirectionMode ;;
            
            #Ce qu'il se passe si le caractère entré est la touche '3'
        	'3')
            	xinput float $idClavier ;
            	echo "Vous avez choisi l'option 3." ;
            	tput cup 10 36 ;
            	sleep 1 ;
            	affichage2 ;
            	xinput reattach $idClavier $idMaitre ;
            	redirectionMode ;;
            
            #Ce qu'il se passe si le caractère entré est la touche 'c'
        	'c')
            	modeCommande=1 ; couleurMode ; affichage2 ; redirectionMode ;;
            
            #Ce qu'il se passe si le caractère entré est la touche 'q'
        	'q')
            	echo "Fin du programme." ;
            	stty sane ;
            	xinput reattach $idClavier $idMaitre ;
            	exit ;;
            
    	esac
    done
	
}

#Le mode commande là où je rencontre mon problème de touche 'Échap'
commande() {
	
	trap commandeInterrompue 2 ;
	tput cup 10 7 ; echo -e "                              " ;
	tput cup 10 7 ;
	read cmdUtilisateur ;
	xinput float $idClavier ;
	tput cup 12 0 ; echo -e "Vous avez tapé la commande : $cmdUtilisateur . " ;
	
	if		[[ "$cmdUtilisateur" == "q" ]]
	then	stty sane ;
			xinput reattach $idClavier $idMaitre ;clear ;
			exit ;
	fi
	
	sleep 3 ;
	tput cup 12 0 ; echo -e "                                                                                " ;
	affichage2 ;
	xinput reattach $idClavier $idMaitre ;
	commande ;
	
}

#La fonction vers laquelle on est redirigée lorsque l'on appuie sur 'Échap' en mode Commande
commandeInterrompue() {
	
	clear
	stty sane ;
	modeCommande=0 ;
	couleurMode ;
	affichage1 ;
	affichage2 ;
	redirectionMode ;
	
}

###############################################

##########   Fonctions d'affichage   ##########

affichage1() {
	
	tput cup 0 0 ; echo -e "=-= Version 2 de la fonctionnalité de gameplay dual-mode pour SSFD =-="
	tput cup 1 0 ; echo -e "Le joueur peut passer du mode 'Touche' au mode 'Commande' en un instant."
	tput cup 3 0 ; echo -e "[1] Option 1"
	tput cup 4 0 ; echo -e "[2] Option 2"
	tput cup 5 0 ; echo -e "[3] Option 3"
	tput cup 7 0 ; echo -e "Appuyez sur les chiffres 1,2 ou 3 pour choisir votre option."
	tput cup 8 0 ; echo -e "Appuyez sur 'c' pour rentrer en mode 'Commande' ci-dessous. "
	
}

affichage2() {
	
	tput cup 10 0 ; echo -e "                                   "
	tput cup 10 0 ; echo -e "${couleurCommande}[c]${couleurTexteDefaut} : "
	
}

###############################################

########## Déroulement du programme  ##########

clear

couleurMode ;
affichage1 ;
affichage2 ;
redirectionMode ;

###############################################

En fait, je ne pourrais dire exactement quels sont les processus mis en jeu dans mon bug, pour ce qui est de ce vrai code, et c'est surtout là dessus que je pense avoir un besoin d'éclaircissement, si possible.


Merci beaucoup de prendre et d'avoir pris autant de temps pour me déflouter quand à mon problème ! smile

Hors ligne

#6 Le 17/05/2020, à 18:57

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Je n'ai pas vraiment vu de question dans ton dernier post, mais au vu de ton code, je suppose que tu obtiens toujours le même comportement problématique qu'au début : la touche échap ne semble agir qu'une seule fois, puis rester inactive.
Ton problème est toujours le même, et il est double :

  • tu imbriques trop tes fonctions qui s'appellent les unes les autres sans se terminer correctement (en renvoyant une valeur retour par return, comme je l'ai fait avec fonction() dans mon post #2), ce qui fait qu'on ne sort jamais de la fonction appelée par trap ;

  • tu n'utilises toujours pas la définition de fonction avec des parenthèses au lieu des accolades (ici, il faudrait le faire pour commande()), donc ton script n'engendre pas de sous-processus pour ses fonctions, et donc le pkill -P $$ en ligne 24 est sans effet.

Pour le premier point, la solution que je te propose en #2 est d'écrire une boucle explicite dans le corps principal du script :

while ! fonction; do :; done

au lieu d'engendrer une boucle implicite mal maitrisée par appels imbriqués de fonctions.

La fonction appelée dans la boucle while renverra une valeur différente de 0 si elle est tuée, continuant ainsi la boucle, et elle renverra 0 si on satisfait la condition de sortie "$cmdUtilisateur" == "q", terminant ainsi la boucle, puis le script.
Par ailleurs, la commande trap devrait se trouver dans le corps principal du script, en dehors de toute boucle (explicite ou implicite), avec les paramétrages introductifs, après les définitions de fonctions, comme en #2.

Pour le second point, il faut simplement changer les accolades en parenthèses :

commande() (
  …
)

au lieu de

commande() {
  …
}

Hors ligne

#7 Le 17/05/2020, à 20:17

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Voilà un possible réagencement, en changeant les choses à minima :

#!/bin/bash
#Version 2 de la fonctionnalité de gameplay dual-mode pour SSFD

############# Fonctions de modes ##############

#Cette fonction est constamment appelée dès la sortie d'un mode, pour passer à l'autre
redirectionMode() {
	if [[ "$modeCommande" == 0 ]]
	then touche
	else commande
	fi
}

#Le mode touche n'a à priori aucun problème
touche() {
	tput cup 10 7
	while read -rsn1 caractere
	do
		case $caractere in
			#Ce qu'il se passe si le caractère entré est la touche '1'
			'1')
				xinput float $idClavier
				echo "Vous avez choisi l'option 1."
				tput cup 10 36
				sleep 1
				affichage2
				xinput reattach $idClavier $idMaitre
				;;

			#Ce qu'il se passe si le caractère entré est la touche '2'
			'2')
				xinput float $idClavier
				echo "Vous avez choisi l'option 2."
				tput cup 10 36
				sleep 1
				affichage2
				xinput reattach $idClavier $idMaitre
				;;

			#Ce qu'il se passe si le caractère entré est la touche '3'
			'3')
				xinput float $idClavier
				echo "Vous avez choisi l'option 3."
				tput cup 10 36
				sleep 1
				affichage2
				xinput reattach $idClavier $idMaitre
				;;
				
			#Ce qu'il se passe si le caractère entré est la touche 'c'
			'c')
				modeCommande=1 ; couleurMode ; affichage2 ;;

			#Ce qu'il se passe si le caractère entré est la touche 'q'
			'q')
				echo "Fin du programme."
				stty sane
				xinput reattach $idClavier $idMaitre
				exit
				;;
			*)
				echo "Caractère invalide." ;;
		esac
	done
}

#Le mode commande là où je rencontre mon problème de touche 'Échap'
commande() (
	tput cup 10 7 ; echo -e "                              "
	tput cup 10 7
	read cmdUtilisateur
	xinput float $idClavier
	tput cup 12 0 ; echo -e "Vous avez tapé la commande : $cmdUtilisateur . "

	if [[ "$cmdUtilisateur" == "q" ]]; then
		stty sane
		xinput reattach $idClavier $idMaitre
		clear
		exit
	fi

	sleep 3
	tput cup 12 0 ; echo -e "                                                                                "
	affichage2
	xinput reattach $idClavier $idMaitre
)

#La fonction vers laquelle on est redirigée lorsque l'on appuie sur 'Échap' en mode Commande
commandeInterrompue() {
	pkill -P $$
	clear
	stty sane
	modeCommande=0
	couleurMode
	affichage1
	affichage2
}

############ Fonctions d'affichage ############

#Prompt rouge = on est en mode Touche ; Prompt vert = on est en mode Commande
couleurMode() {
	if [[ "$modeCommande" == 0 ]]
	then couleurCommande='\033[31m'
	else couleurCommande='\033[32m'
	fi
}

affichage1() {
	tput cup 0 0 ; echo -e "=-= Version 2 de la fonctionnalité de gameplay dual-mode pour SSFD =-="
	tput cup 1 0 ; echo -e "Le joueur peut passer du mode 'Touche' au mode 'Commande' en un instant."
	tput cup 3 0 ; echo -e "[1] Option 1"
	tput cup 4 0 ; echo -e "[2] Option 2"
	tput cup 5 0 ; echo -e "[3] Option 3"
	tput cup 7 0 ; echo -e "Appuyez sur les chiffres 1,2 ou 3 pour choisir votre option."
	tput cup 8 0 ; echo -e "Appuyez sur 'c' pour rentrer en mode 'Commande' ci-dessous. "
}

affichage2() {
	tput cup 10 0 ; echo -e "                                   "
	tput cup 10 0 ; echo -e "${couleurCommande}[c]${couleurTexteDefaut} : "
}

########## Paramétrage introductif ############

resize -s 24 80

modeCommande=0
couleurTexteDefaut='\033[0m'

#Variables pour la désactivation du clavier###
idClavier=$(xinput list | grep 'AT Translated Set 2 keyboard' | cut -d '=' -f 2 | cut -d '[' -f 1 | cut -d ' ' -f 1)
idMaitre=$(xinput list | grep 'AT Translated Set 2 keyboard' | cut -d '=' -f 2 | cut -d '(' -f 2 | cut -d ')' -f 1 | cut -d ' ' -f 2)
stty intr '^['
trap commandeInterrompue 2
clear

########## Déroulement du programme ###########

couleurMode
affichage1
affichage2
while true; do redirectionMode; done

###############################################

Je n'ai pas testé ce code, je l'ai juste remanié à la volée : à toi de tester et déboguer au besoin tongue
Les principaux points revus sont les suivants :

  • une boucle principale explicite, cette fois-ci en while true; do … done, qui indique donc par elle-même que la condition d'arrêt se trouve ailleurs, en l'occurrence dans les exit situés dans touche() et commande() ;

  • des fonctions qui ont toutes un début et une fin, sans imbrication ;

  • la fonction commande(), où une interruption par échap peut avoir lieu, mise entre parenthèses ;

  • un cas par défaut pour le case … esac, quelques modifications de forme, indentation, etc.

Si la fonction touche() devait elle aussi pouvoir être interrompue par échap, alors il faudrait elle aussi la mettre entre parenthèses.
Mais ça demanderait quelques modifications supplémentaires, car elle modifie une variable globale et écrit des messages sur la sortie standard…

Dernière modification par kamaris (Le 17/05/2020, à 20:23)

Hors ligne

#8 Le 17/05/2020, à 20:40

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

D'ailleurs, petite modif supplémentaire qui correspond sans doute mieux à ce que tu veux faire : déplacement des commandes trap et stty dans redirectionMode(), avec activation / désactivation en encadrement de commande(), pour restreindre l'effet de la touche échap à cette seule fonction :

#!/bin/bash
#Version 2 de la fonctionnalité de gameplay dual-mode pour SSFD

############# Fonctions de modes ##############

#Cette fonction est constamment appelée dès la sortie d'un mode, pour passer à l'autre
redirectionMode() {
	if [[ "$modeCommande" == 0 ]]; then
		touche
	else
		stty intr '^['
		trap commandeInterrompue 2
		commande
		stty sane
		trap 2
	fi
}

#Le mode touche n'a à priori aucun problème
touche() {
	tput cup 10 7
	while read -rsn1 caractere
	do
		case $caractere in
			#Ce qu'il se passe si le caractère entré est la touche '1'
			'1')
				xinput float $idClavier
				echo "Vous avez choisi l'option 1."
				tput cup 10 36
				sleep 1
				affichage2
				xinput reattach $idClavier $idMaitre
				;;

			#Ce qu'il se passe si le caractère entré est la touche '2'
			'2')
				xinput float $idClavier
				echo "Vous avez choisi l'option 2."
				tput cup 10 36
				sleep 1
				affichage2
				xinput reattach $idClavier $idMaitre
				;;

			#Ce qu'il se passe si le caractère entré est la touche '3'
			'3')
				xinput float $idClavier
				echo "Vous avez choisi l'option 3."
				tput cup 10 36
				sleep 1
				affichage2
				xinput reattach $idClavier $idMaitre
				;;
				
			#Ce qu'il se passe si le caractère entré est la touche 'c'
			'c')
				modeCommande=1 ; couleurMode ; affichage2 ;;

			#Ce qu'il se passe si le caractère entré est la touche 'q'
			'q')
				echo "Fin du programme."
				xinput reattach $idClavier $idMaitre
				exit
				;;
			*)
				echo "Caractère invalide." ;;
		esac
	done
}

#Le mode commande là où je rencontre mon problème de touche 'Échap'
commande() (
	tput cup 10 7 ; echo -e "                              "
	tput cup 10 7
	read cmdUtilisateur
	xinput float $idClavier
	tput cup 12 0 ; echo -e "Vous avez tapé la commande : $cmdUtilisateur . "

	if [[ "$cmdUtilisateur" == "q" ]]; then
		stty sane
		xinput reattach $idClavier $idMaitre
		clear
		exit
	fi

	sleep 3
	tput cup 12 0 ; echo -e "                                                                                "
	affichage2
	xinput reattach $idClavier $idMaitre
)

#La fonction vers laquelle on est redirigée lorsque l'on appuie sur 'Échap' en mode Commande
commandeInterrompue() {
	pkill -P $$
	clear
	modeCommande=0
	couleurMode
	affichage1
	affichage2
}

############ Fonctions d'affichage ############

#Prompt rouge = on est en mode Touche ; Prompt vert = on est en mode Commande
couleurMode() {
	if [[ "$modeCommande" == 0 ]]
	then couleurCommande='\033[31m'
	else couleurCommande='\033[32m'
	fi
}

affichage1() {
	tput cup 0 0 ; echo -e "=-= Version 2 de la fonctionnalité de gameplay dual-mode pour SSFD =-="
	tput cup 1 0 ; echo -e "Le joueur peut passer du mode 'Touche' au mode 'Commande' en un instant."
	tput cup 3 0 ; echo -e "[1] Option 1"
	tput cup 4 0 ; echo -e "[2] Option 2"
	tput cup 5 0 ; echo -e "[3] Option 3"
	tput cup 7 0 ; echo -e "Appuyez sur les chiffres 1,2 ou 3 pour choisir votre option."
	tput cup 8 0 ; echo -e "Appuyez sur 'c' pour rentrer en mode 'Commande' ci-dessous. "
}

affichage2() {
	tput cup 10 0 ; echo -e "                                   "
	tput cup 10 0 ; echo -e "${couleurCommande}[c]${couleurTexteDefaut} : "
}

########## Paramétrage introductif ############

resize -s 24 80

modeCommande=0
couleurTexteDefaut='\033[0m'

#Variables pour la désactivation du clavier###
idClavier=$(xinput list | grep 'AT Translated Set 2 keyboard' | cut -d '=' -f 2 | cut -d '[' -f 1 | cut -d ' ' -f 1)
idMaitre=$(xinput list | grep 'AT Translated Set 2 keyboard' | cut -d '=' -f 2 | cut -d '(' -f 2 | cut -d ')' -f 1 | cut -d ' ' -f 2)
clear

########## Déroulement du programme ###########

couleurMode
affichage1
affichage2
while true; do redirectionMode; done

###############################################

Hors ligne

#9 Le 17/05/2020, à 21:02

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Ouah !!! yikes
Je ne demandais pas autant d'investissement de ta part, mais ça reste néanmois ultra généreux et très apprécié, merci ! wink
Je vais regarder à tout ça, je n'ai pas encore lu. Cette nuit, je ne pourrais pas et, travaillant dans un collège, je devrais reprendre sous peu (au mieux dès demain) en présentiel à 50% donc n'ayant aucune idée de mes horaires, et donc de mon temps libre, je vais essayer de gratter un peu de temps, ne serait-ce que demain, pour prendre en compte tous les conseils que je viens de voir et les appliquer : je suis sûr qu'il y a moyen de faire quelque chose d'ultra propre !

Encore merci, et je reviendrai poster après avoir travaillé une version 3 du script, histoire d'avoir quelque chose de bien plus correct ! wink

Hors ligne

#10 Le 17/05/2020, à 21:17

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Pas de problème wink
Et bon courage pour le collège, où il n'est malheureusement plus possible d'appliquer les bonnes vieilles méthodes :

for enfant in college/*; do
  paire_de_claques "$enfant"
done

big_smile

Hors ligne

#11 Le 18/05/2020, à 20:20

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Re pour aujourd'hui !

Alors, pour l'instant, je suis en train de remanier mon code. Il s'avère que pour l'instant, il y a de nouveaux bugs qui sont apparus. La couleur du prompt semble se déclencher indépendamment des fonctions touche() et commande(), et c'est réellement problématique sur le plan cognitif, pour comprendre ce qu'il se passe dans la machine.

Par ailleurs, je patauge toujours par rapport aux notions : j'ai vu que tu voulais me dire qu'il est important que les fonctions ont un début et une fin, et qu'il est important qu'elles se finissent toutes, j'ai vu que tu voulais me dire qu'il ne fallait pas que les fonctions soient trop imbriquées, mais je n'ai pas compris plusieurs choses :
qu'est-ce que ça veut dire, une fonction qui se finit bien ?
--> En quoi est-ce que c'est important qu'elle se finit bien ? En quoi l'inverse est problématique ?
--> Qu'est-ce que ça veut dire, des fonctions trop imbriquées ?
--> À quoi ça sert de ne pas les imbriquer ( avantages/inconvénients) ?

J'ai bien lu dans ton post #2 que l'imbrication de mes fonctions semble être la source de mon problème, mais j'ai encore du mal à avoir pleinement conscience du pourquoi. Désolé de tourner en rond, j'ai l'impression de ne pas avoir tant avancé depuis le début et l'impression de te faire perdre ton temps, c'est juste qu'il y a des concepts, qui, dès qu'ils sont isolés, me sont compréhensible, mais une fois mis en relation entre eux, m'échappent.


<<< Petit hors-sujet >>>

kamaris a écrit :

Et bon courage pour le collège, où il n'est malheureusement plus possible d'appliquer les bonnes vieilles méthodes :

Merci, ça va, là, je reste en 100% télétravail pour le moment et reprends en 100% présentiel le 03 Juin, pré-rentrée le 02 donc pour X raison, même si on ne me l'a pas dit ouvertement, à priori, sauf si changement, dans le collège où je bosse, les gamins devraient reprendre le 03 Juin, ça me laisse le temps de me préparer psychologiquement (oui, il y en a qui mériteraient plus qu'une boucle for big_smile).
<<< / Petit hors-sujet >>>

Dernière modification par Brice Jeunieaux (Le 18/05/2020, à 20:22)

Hors ligne

#12 Le 18/05/2020, à 21:12

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

En un mot, il faut que tu aies à l'esprit une vue claire de ton programme : ce qu'il fait, comment il le fait, avec quelles ressources, quelles articulations internes…
Le fait que tu ne parviennes pas à le débuguer montre que ça n'est pas le cas.
C'est une raison suffisante pour ne pas imbriquer les fonctions dans tous les sens : on ne sait plus où on en est, qui fait quoi, qui a fait quoi, qui fera quoi ensuite.

Une fonction, de manière universelle, à des arguments d'entrée, une sortie éventuellement vide, et un code retour.
C'est le concept même de fonction que de recevoir quelque chose en entrée, de le transformer en interne, et de renvoyer quelque chose en sortie.
Ici, tes fonctions n'en sont pas : ce ne sont que des lieux de passage, et tes appels de fonction s'apparentent plus à des goto qu'autre chose : technique largement déconseillée qu'on utilise plus qu'en cobol ! big_smile

Dans le cas particulier de trap, il faut que la fonction appelée lorsqu'il capture SIGINT lui rende la main pour qu'il capture à nouveau le signal.
Donc soit qu'elle soit lancée en arrière plan (hors sujet ici), soit qu'elle se termine par un return explicite ou implicite (en exécutant la dernière ligne de son corps).

Voilà en gros l'idée, et je vais avoir du mal à être plus explicatif sans noyer l'explication dans l'explication.
Essaie de comparer le déroulement de ton code en #5, à celui que je te propose en #8.
Je ne prétends pas du tout donner ici une référence, j'ai juste essayé de redresser un peu l'ensemble, mais tu verras que le déroulement y est plus clair, plus explicite, que les choses ont un début et une fin, aussi bien localement que globalement…

Hors ligne

#13 Le 19/05/2020, à 15:26

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Bonjour / bonsoir,

je viens de retravailler mon programme, tant sur papier que sur machine, afin d'essayer de régler mon problème d'origine.

Si je comprends bien, pour finir une fonction B proprement, celle-ci doit retourner à la fonction-mère A, d'où elle est émise, afin que cette fonction B puisse réellement être close, au lieu d'encore et encore renvoyer vers une autre fonction ? Si oui, alors peut-être que mon code rectifié ci-dessous est bon. Dans le mode "Touche", pour chaque option du 'case' (exceptée celle qui quitte le terminal en appuyant sur 'q'), j'ai mis un 'return' à la fin. J'ai fait ça pour justement dire au programme "maintenant toi la fonction B, tu reviens à la fonction-mère A au lieu de créer une fonction-fille copie de la fonction A". Est-ce que c'est la / une bonne pratique ?


Ci-dessous mon code :
--- Les changement mineurs :     noms plus explicite de certaines fonctions (ex : affichagePrompt au lieu de affichage2, colorationPrompt au lieu de couleurMode, etc...) ; commentaires + détails pour ce que j'estimais nécessaire pour moi-même ; quelques broutilles de mise en forme, espacements, retour à la ligne, une seule commande par ligne pour aérer, etc...
--- Les changements majeurs :     ajout des 'return' dans le 'case' comme mentionné ci-dessus
--- Les changements majeurs abandonnés / peu sûrs :      j'ai voulu supprimé les fonctions de coloration et d'affichage du prompt pour en intégrer directement les commandes à la fonction de redirection. Le but visé était d'avoir une seule fonction d'affichage afin d'alléger la partie "Fonctions d'affichage" située vers la fin du programme. Seulement, vu que dans le 'case' du mode "Touche", on fait appel à ces fonctions, je pense que si j'aurais fait cela, alors ça aurait pu aller à l'encontre des commandes 'return' (à condition que j'en ai bien compris l'intérêt). Dans le doute de mes connaissances, j'ai préféré laisser pour le moment, et y aller petit à petit.

#!/bin/bash
#Version 3 de la fonctionnalité de gameplay dual-mode pour SSFD.

############# Fonctions de modes ##############

#Cette fonction est appelée dans la boucle while true, et se situe "tout en haut" dans le programme.
#Elle permet de reconnaître dans quel "mode" se situe l'utilisateur, et l'envoie vers la fonction
#du mode d'entrée approprié (Mode "Touche" : touche() ; Mode "Commande" : commande() ).

redirectionMode() {
	
	if		[[ "$modeCommande" == 0 ]]
	then	touche
	else	stty intr '^['
			trap commandeInterrompue 2
			commande
			stty sane
			trap 2
	fi
	
}

#La fonction du mode "Touche".
touche() {
	
	tput cup 10 6
	
	while read -rsn1 caractere
	do
		case $caractere in
			#Ce qu'il se passe si le caractère entré est la touche '1'.
			'1')
				xinput float $idClavier
				echo "Vous avez choisi l'option 1."
				tput cup 10 35
				sleep 1
				affichagePrompt
				xinput reattach $idClavier $idMaitre
				return
				;;

			#Ce qu'il se passe si le caractère entré est la touche '2'.
			'2')
				xinput float $idClavier
				echo "Vous avez choisi l'option 2."
				tput cup 10 35
				sleep 1
				affichagePrompt
				xinput reattach $idClavier $idMaitre
				return
				;;

			#Ce qu'il se passe si le caractère entré est la touche '3'.
			'3')
				xinput float $idClavier
				echo "Vous avez choisi l'option 3."
				tput cup 10 35
				sleep 1
				affichagePrompt
				xinput reattach $idClavier $idMaitre
				return
				;;
				
			#Ce qu'il se passe si le caractère entré est la touche 'c'.
			'c')
				modeCommande=1
				colorationPrompt
				affichagePrompt
				return
				;;

			#Ce qu'il se passe si le caractère entré est la touche 'q'.
			'q')
				echo "Fin du programme."
				xinput reattach $idClavier $idMaitre
				exit
				;;
			
			#Ce qu'il se passe si l'utilisateur appuie sur n'importe quelle autre touche.
			*)
				;;
		esac
	done
}

#La fonction du mode "Commande".
commande() (
	
	tput cup 10 6
	#Effacement de toute trace de texte à droite du prompt.
	echo -e "                              "
	tput cup 10 6
	#Lecture en entrée
	read cmdUtilisateur
	#Effet de la commande 'read'
	xinput float $idClavier
	tput cup 12 0
	echo -e "Vous avez tapé la commande : $cmdUtilisateur . "
	
	#Si l'utilisateur a entré un unique caractère 'q', alors on quitte le programme (de manière
	#similaire à la touche 'q' en mode "Touche").
	if		[[ "$cmdUtilisateur" == "q" ]]
	then	stty sane
			xinput reattach $idClavier $idMaitre
			clear
			exit
	fi
	
	sleep 3
	tput cup 12 0
	echo -e "                                                                                "
	affichagePrompt
	xinput reattach $idClavier $idMaitre
	
)

#La fonction vers laquelle on est redirigée lorsque l'on appuie sur 'Échap' en mode Commande.
commandeInterrompue() {
	
	pkill -P $$
	clear
	modeCommande=0
	colorationPrompt
	affichageInterface
	affichagePrompt
	
}

############ Fonctions d'affichage ############

#Prompt rouge = on est en mode Touche ; Prompt vert = on est en mode Commande.
colorationPrompt() {
	
	if [[ "$modeCommande" == 0 ]]
	then couleurCommande='\033[31m'	#Rouge
	else couleurCommande='\033[32m' #Vert
	fi
	
}

affichageInterface() {
	
	tput cup 0 0 ; echo -e "=-= Version 2 de la fonctionnalité de gameplay dual-mode pour SSFD =-="
	tput cup 1 0 ; echo -e "Le joueur peut passer du mode 'Touche' au mode 'Commande' en un instant."
	tput cup 3 0 ; echo -e "[1] Option 1"
	tput cup 4 0 ; echo -e "[2] Option 2"
	tput cup 5 0 ; echo -e "[3] Option 3"
	tput cup 7 0 ; echo -e "Appuyez sur les chiffres 1,2 ou 3 pour choisir votre option."
	tput cup 8 0 ; echo -e "Appuyez sur 'c' pour rentrer en mode 'Commande' ci-dessous. "
	
}

affichagePrompt() {
	
	tput cup 10 0 ; echo -e "                                   "
	tput cup 10 0 ; echo -e "${couleurCommande}[c]${couleurTexteDefaut} : "
	
}

########## Paramétrage introductif ############

resize -s 24 80

modeCommande=0
couleurTexteDefaut='\033[0m'

#Variables pour la désactivation du clavier###
idClavier=$(xinput list | grep 'AT Translated Set 2 keyboard' | cut -d '=' -f 2 | cut -d '[' -f 1 | cut -d ' ' -f 1)
idMaitre=$(xinput list | grep 'AT Translated Set 2 keyboard' | cut -d '=' -f 2 | cut -d '(' -f 2 | cut -d ')' -f 1 | cut -d ' ' -f 2)

clear

###############################################



########## Déroulement du programme ###########

colorationPrompt
affichageInterface
affichagePrompt
while true; do redirectionMode; done

###############################################

Du coup, maintenant, mon problème semble résolu, en pratique, mais est-ce que j'ai proprement codé, là est la question.

Hors ligne

#14 Le 19/05/2020, à 15:33

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Je poste dans un second message pour pas faire trop surchargé.

Il y a une question qui me trottine depuis un bout de temps et qui n'a rien à voir avec la problématique d'origine, mais je ne pense pas nécessaire de créer un sujet de discussion dédié (si ?). Alors voilà je me lance :

Comme on le voit dans mon programme, j'utilise des commandes, 'xinput float' et 'xinput reattach' qui me permettent de désactiver l'usage du clavier.
J'ai implémenté cela dans le programme dans le but de remédier aux affichages parasites de caractères qui peuvent être causés par un testeur bourrin impatient de rentrer des commandes et autres.

Sauf que là est ma question, est-ce que ce n'est pas un problème en terme de sécurité ? Est-ce que, peu importe l'utilisateur qui teste mon programme, si celui-ci fait 'xinput' dans son terminal, est-ce qu'il obtient bien les même lignes retournées que j'exploite dans mon code ? J'ai peur qu'il puisse y avoir des failles dans cette fonctionnalité et que l'utilisateur se retrouve avec son clavier désactivé et doit donc redémarrer sa machine (c'est comme ça que je fait quand j'ai des accidents de 'xinput float' vu que je sais pas comment le régler autrement).

Dernière modification par Brice Jeunieaux (Le 19/05/2020, à 15:34)

Hors ligne

#15 Le 19/05/2020, à 19:11

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Oui, là pour moi c'est au moins compréhensible : on voit où ça démarre, quels principaux chemins ça peut suivre, et où ça se termine.

Pour les return dans le case … esac, je ne les avais pas mis, car ils sont implicites : si on atteint la dernière ligne (exécutée) d'une fonction, elle renvoie le code retour de la dernière commande qu'elle a exécutée en interne.
Tu peux très bien les mettre si tu trouves ça plus clair et explicite, mais en général, on ne les met que si on veut forcer la fonction à quitter prématurément, et / ou si on veut forcer un code retour autre que celui par défaut.

D'ailleurs, une remarque concernant l'utilisation de trap : il y a bien plus simple en l'occurrence que ma première réaction, consistant à définir la fonction mère avec des parenthèses pour en faire un sous-processus tuable.
Il suffit justement de mettre un return dans le trap, pour forcer la fonction mère à se terminer, une fois que la fonction appelée par trap a elle-même fini son travail :

trap 'commandeInterrompue; return 1' 2

Et on peut ainsi virer le pkill -P $$ de commandeInterrompue(), qui ne sert plus à rien, et remettre commande() avec une définition entre crochets :

commande() {
…
}

Pour les fonctions d'affichage, je pense que leur utilisation est correcte comme ça : on s'en sert où il faut qu'on s'en serve (et ça ne se limite pas à la fonction de redirection), et on se sert parfois d'une seule, parfois de deux, parfois de trois, donc on ne peut pas non plus les regrouper en une ou deux.
Maintenant, c'est toi qui sais quel résultat ça doit donner au final, donc peut-être que je ne vois pas certaines simplifications possibles…

Pour répondre un peu plus à ta question sur les bonnes pratiques : une chose qui pourrait être faite, pour aller plus loin dans la fonctionnalisation de tes fonctions, c'est d'éviter de se servir de variables globales, pour passer plutôt des paramètres aux fonctions, et leur faire renvoyer quelque chose :

fonction() {
…
echo 'quelque chose'
}

var='valeur initiale'
…
var=$(fonction "$param1" … "$paramN")

au lieu de

fonction() {
…
var_globale='quelque chose'
…
}

var_globale='valeur initiale'
…
fonction

Mais c'est vrai qu'ici ça ne s'y prête que moyennement : tu as peu de variables, et tes fonctions font très peu de transformations de données en interne.
Donc c'est peut-être pas la peine de vouloir à tout prix appliquer cette règle.

Enfin, pour xinput, je ne sais pas : je ne connais pas, et j'ai essayé les commandes du script dans un terminal ou un script chez moi, et ça ne me désactive rien du tout.
Je pense donc que si tu as plus de questions là-dessus, tu pourrais effectivement ouvrir un nouveau sujet, car celui-là est déjà bien rempli smile

Hors ligne

#16 Le 19/05/2020, à 22:59

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

kamaris a écrit :

Pour les return dans le case … esac, je ne les avais pas mis, car ils sont implicites : si on atteint la dernière ligne (exécutée) d'une fonction, elle renvoie le code retour de la dernière commande qu'elle a exécutée en interne.
Tu peux très bien les mettre si tu trouves ça plus clair et explicite, mais en général, on ne les met que si on veut forcer la fonction à quitter prématurément, et / ou si on veut forcer un code retour autre que celui par défaut.

Là où j'ai du mal à cerner le pourquoi, c'est qu'en passant en commentaire les returns que j'ai mis, le programme ne fait pas exactement ce que l'on attend de lui, au niveau du 'case'. Par exemple, pour le 'case' de la touche 'c', sans la commande return, je n'ai pas l'impression que le programme, ayant fini de lire la partie de code concernée de la fonction-fille, revient vers la fonction-mère, ce qui fait qu'en appuyant sur la touche 'c', il y a juste la coloration et l'affichage du prompt qui se fait, mais on ne passe pas à la fonction "commande()".

Partie de code concernée de la fonction-fille :

#Ce qu'il se passe si le caractère entré est la touche 'c'.
			'c')
				modeCommande=1
				colorationPrompt
				affichagePrompt
				#return		#Mon return passé en commentaire
				;;

Fonction-mère :

redirectionMode() {
	
	if		[[ "$modeCommande" == 0 ]]
	then	touche
	else	stty intr '^['
			trap commandeInterrompue 2
			commande
			stty sane
			trap 2
	fi
	
}

Ma logique voudrait que, comme tu as dit, s'il n'y a pas besoin de mentionner le 'return' car déjà présent implicitement, alors une fois que la partie 'c') de mon case arrive à sa finen double point-virgule, la suite de la fonction-mère "redirectionMode()" reprend, après l'appel de la fonction "commande()".
Pourtant, si le programme agissait bien ainsi, alors on n'aurait pas de problème, et pourtant, sans le 'return', j'en rencontre quand même un.

Hors ligne

#17 Le 19/05/2020, à 23:08

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

kamaris a écrit :

D'ailleurs, une remarque concernant l'utilisation de trap : il y a bien plus simple en l'occurrence que ma première réaction, consistant à définir la fonction mère avec des parenthèses pour en faire un sous-processus tuable.
Il suffit justement de mettre un return dans le trap, pour forcer la fonction mère à se terminer, une fois que la fonction appelée par trap a elle-même fini son travail :

trap 'commandeInterrompue; return 1' 2

Et on peut ainsi virer le pkill -P $$ de commandeInterrompue(), qui ne sert plus à rien, et remettre commande() avec une définition entre crochets :

commande() {

}

Là dessus, j'ai pas tout compris ta démarche avancée, je pense que je vais y aller tout doucement, je préfère comprendre pas grand chose et devoir relire des cours, quitte à stagner sur le projet, que d'avoir des trucs que je ne comprends pas dans mon code. lol


Quant à ton histoire de bonnes pratiques des variables globales et paramètres de fonctions, cela pourrait m'être utile parce que j'ai encore pas mal de code du projet source que je n'ai pas montré ici vu que ce n'est pas le sujet. Dans le futur, cela risque de me concerner vu que j'estime devoir créer pas mal de variables temporaires pour le traitement dans les fonctions. Je garde cette histoire de bonnes pratiques sous la main, du coup. wink


Pour mon histoire de 'xinput', pas de souci, j'ouvrirai un sujet quand j'aurais fini le développement prioritaire de certaines parties du logiciel.

Hors ligne

#18 Le 20/05/2020, à 00:21

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

Ah oui, pour le case c'est vrai qu'il faut quelque chose, à cause du read interactif qui redemande toujours un caractère sinon.
Il faut soit un break pour sortir de la boucle while, et terminer la fonction implicitement, soir un return explicite.
Par contre il ne faut pas forcément mettre ça pour chaque item du case, c'est à voir selon ce que ça doit faire, si on doit continuer à demander à l'utilisateur d'entrer un caractère ou non…

Un truc bien utile que tu peux utiliser pour auditer ton code, c'est shellchek : https://www.shellcheck.net/
C'est installable en local via les dépôts.
Je viens d'ailleurs de voir que c'est recommandé par les devs de chez google dans leur style guide bash : https://google.github.io/styleguide/she … s-and-bugs

Hors ligne

#19 Le 21/05/2020, à 17:09

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

kamaris a écrit :

Ah oui, pour le case c'est vrai qu'il faut quelque chose, à cause du read interactif qui redemande toujours un caractère sinon.
Il faut soit un break pour sortir de la boucle while, et terminer la fonction implicitement, soir un return explicite.
Par contre il ne faut pas forcément mettre ça pour chaque item du case, c'est à voir selon ce que ça doit faire, si on doit continuer à demander à l'utilisateur d'entrer un caractère ou non…

Un truc bien utile que tu peux utiliser pour auditer ton code, c'est shellchek : https://www.shellcheck.net/
C'est installable en local via les dépôts.
Je viens d'ailleurs de voir que c'est recommandé par les devs de chez google dans leur style guide bash : https://google.github.io/styleguide/she … s-and-bugs

Deux liens géniaux pour le prix d'un, super ! smile

Je vais continuer à me documenter sur les return et autres fonctionnements subtils des boucles, c'est quelque chose que j'ai toujours eu du mal avec, d'où le fait que ça m'a apporté le bug dont ce sujet de discussion fait l'objet.

Encore merci pour toute l'aide apportée, on en ressort un peu plus grand ! (Jusqu'à mes prochaines erreurs, on va dire ... roll)

Hors ligne

#20 Le 21/05/2020, à 19:41

kamaris

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

De rien, et bon développement pour ton jeu !

1590090410.gif

wink

Dernière modification par kamaris (Le 21/05/2020, à 19:42)

Hors ligne

#21 Le 21/05/2020, à 21:22

Brice Jeunieaux

Re : [Résolu] Boucle read : 'stty intr' / 'trap' ne fonctionne qu'une fois.

kamaris a écrit :

De rien, et bon développement pour ton jeu !

http://pix.toile-libre.org/upload/thumb/1590090410.gif

wink

Merci bien, ça avance, lentement mais sûrement ! Bonne journée / soirée / nuitée ! big_smile

Hors ligne