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 04/12/2017, à 23:39

arno_lupin

[résolu] Portée des variables et appels de fonctions ... et sous-shell

salut,
Je ne saisis pas bien ce qu'il se passe ici :

mon_script a écrit :

#!/bin/bash
a=1
fct() { a=2 ; echo "ma fonction" ;}
b=$( fct )
echo "a = $a // b = $b"

$ ./mon_script
a = 1 // b = ma fonction

Pourquoi ma variable "a" est-elle restée à 1 ? Est-ce une histoire de sous-shell ?
Que faire pour y remédier ?

Quelqu'un peut-il m'aider ? Je tourne en rond... sad

Dernière modification par arno_lupin (Le 06/12/2017, à 22:21)


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#2 Le 05/12/2017, à 00:51

Watael

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

salut,

oui, c'est une histoire de sous-shell : la substitution de commande ($()) s'exécute dans un sous-shell.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#3 Le 05/12/2017, à 03:16

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Merci, Watael.
J'avais des soupçons mais j'apprécie la confirmation.
Pourrait-on tout de même récupérer la nouvelle valeur de "a" ?

Dernière modification par arno_lupin (Le 05/12/2017, à 03:17)


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#4 Le 05/12/2017, à 05:25

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

outch !!
Je sens la grosse galère.
La commande "export" paraissait être une solution, mais si c'est le cas je n'arrive pas à l'utiliser correctement. D'un autre côté, j'ai cru comprendre que certains préconisent de placer la variable dans un fichier temporaire pour la réutiliser avant de supprimer le fichier en question... ce qui me semble un peu "bourrin" tout de même.
N'existe-t-il pas de solution simple et efficace pour ce genre de chose ? Ce doit pourtant être un problème assez courant... sad
J'aimerais bien avoir la certitude que ce n'est pas possible avant de chercher d'autres solutions.

Dernière modification par arno_lupin (Le 05/12/2017, à 05:28)


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#5 Le 05/12/2017, à 07:33

pingouinux

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Bonjour,
export var permet de transmettre var à un sous-shell, mais pas de faire remonter l'information.
Pour récupérer une variable définie dans une fonction :

#!/bin/bash
a=1

fct() { a=2 ; echo "ma fonction {}" ;}
fct
echo "a = $a"

fct2() ( a=3 ; echo "ma fonction ()" ;)
fct2
echo "a = $a"

qui donne ce résultat :

ma fonction {}
a = 2
ma fonction ()
a = 2

Note la différence selon que la fonction est définie avec des { }, (exécution dans le shell courant), ou avec des ( ) (exécution dans un sous-shell).

Dernière modification par pingouinux (Le 05/12/2017, à 07:47)

Hors ligne

#6 Le 05/12/2017, à 09:39

Watael

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

tu ne peux pas assigner b à l'intérieur de la fonction ?

il faudrait nous en dire davantage sur ce que tu dois faire plus généralement avec ton script, et ces éléments dans ton script.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#7 Le 05/12/2017, à 12:06

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Merci pour ta réponse pingouinux,

pingouinux a écrit :

export var permet de transmettre var à un sous-shell, mais pas de faire remonter l'information.

J'étais totalement à côté de la plaque. Je comprends à présent qu'on ne peut pas faire remonter l'info simplement. Ce doit être pour cela qu'il me semble avoir lu que l'on devait utiliser un fichier temporaire ! Je vais devoir trouver autre chose.

pingouinux a écrit :

... la fonction est définie avec des { }, (exécution dans le shell courant), ou avec des ( ) (exécution dans un sous-shell).

Je n'avais jamais vu cette forme là pour les fonctions  ( ou alors je ne l'avais jamais remarqué roll ) ! J'aime beaucoup apprendre de nouveaux trucs.
----
Watael,

Watael a écrit :

tu ne peux pas assigner b à l'intérieur de la fonction ?

Malheureusement, non. Mon "b" est en fait un tableau que je manipule en jouant avec l'IFS. Ce serait donc un peu compliqué de tout reprendre. Par contre je pense pouvoir ruser avec le "a" et les codes de retour des fonctions ( return .. ).

Watael a écrit :

il faudrait nous en dire davantage sur ce que tu dois faire plus généralement avec ton script, et ces éléments dans ton script.

Ce n'est pas vraiment un script complexe. J'utilise mkvextract et mkvmerge pour manipuler des fichiers vidéos et insérer du chapitrage. J'ai eu recours à zenity pour la sélection des mkv puis dialog pour le reste. Je me retrouve avec pas mal de fonctions avec lesquelles j'aurais bien aimé contrôler ma boucle principale. Je pense maintenant y parvenir autrement.
----
     Quoi qu'il en soit, merci encore à tout les deux. J'en sais un peu plus sur les sous-shells et je saurais que l'info ne passe pas d'un enfant à un parent ( ça fait un peu parent indigne, dit comme ça wink )

Je note le sujet résolu.


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#8 Le 05/12/2017, à 15:38

erresse

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Bonjour,
Je trouve le sujet intéressant et, en poussant un peu plus loin, pourquoi ne pas récupérer les données en retour de la fonction via "echo" ?

#!/bin/bash
a=1
fct() { echo -n "a=2" ; echo " dans la fonction" ; echo "ma fonction" ;}
b=$( fct )
echo "a = $a // b = $b"

Ce qui donne à l'exécution :

a = 1 // b = a=2 dans la fonction
ma fonction

On peut obtenir les valeurs sur des lignes séparées, ce qui permet de les ventiler dans plusieurs variables...
Qu'en pensez-vous ?


Plus de 50 ans d'informatique, ça en fait des lignes de commandes en console, mais on n'avait pas le choix...
Excellente raison pour, aujourd'hui qu'on le peut, utiliser au maximum les INTERFACES GRAPHIQUES !
Important : Une fois résolu, pensez à clore votre sujet en ajoutant [Résolu] devant le titre du 1er message, et un bref récapitulatif de la solution à la fin de celui-ci. Merci.

Hors ligne

#9 Le 05/12/2017, à 19:25

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Waouh !
Merci erresse,
C'est quasi ce que je cherchais ! Je me permets de reprendre mon petit exemple pour affiner un peu ton idée.

mon_script a écrit :

#!/bin/bash
a=1
fct() { a=2 ; echo $a ; echo "le retour de ma fonction" ;}
ifs=$IFS IFS=$'\n'                    # on évite les pb d'espaces dans le second "echo"
retour=( $( fct ) )
IFS=$ifs
a=${retour[0]}
b=${retour[1]}
echo "a = $a // b = $b"

et... (roulement de tambour)... ça marche ! ( comme quoi les parents, parfois, écoutent eux-aussi les enfants wink )

$ ./mon_script
a = 2 // b = le retour de ma fonction

Alors là bravo erresse !
Si quelqu'un d'autre à des idées ça peut toujours aider.


Puisque cela à l'air d'en intéresser d'autres, je ré-ouvre la discussion ( j'enlève [résolu] un moment )

Dernière modification par arno_lupin (Le 05/12/2017, à 20:22)


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#10 Le 05/12/2017, à 19:57

pingouinux

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Pour sauvegarder et modifier IFS, je ferais ceci :

ifs=$IFS; IFS=$'\n'

et pour le restaurer :

IFS=$ifs

Hors ligne

#11 Le 05/12/2017, à 20:21

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

oups...
Oui, bien sûr. "ifs=IFS" et "IFS=ifs" est une belle coquille. tongue
Le ";" reste optionnel dans ce cas.
Je modifie mon message précédent.
merci pour ta relecture

Dernière modification par arno_lupin (Le 05/12/2017, à 20:28)


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#12 Le 05/12/2017, à 20:25

Watael

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

sans modification "permanente" de l'IFS :

IFS=$'\n' retour=( $(fct) )

avec la réserve que le retour de la fonction ne peut plus être sur plusieurs lignes, mais on peut toujours choisir un séparateur plus rare : µ.
sur le même modèle, un peu plus lourd :

IFS=$'\n' read -d '' -r a retour < <(fct)

et moins problématique, car retour prend tout le reste.

oops, oops, oops ! read ne lit que a, puisqu'il s'intérrompt sur entrée; je révise ma copie...
CORRIGÉ

Dernière modification par Watael (Le 05/12/2017, à 20:35)


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#13 Le 05/12/2017, à 20:46

Compte anonymisé

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

erresse a écrit :

Qu'en pensez-vous ?

Avis personnel : moi je pense que c'est complètement farfelu, il suffit de ne pas utiliser de sous-shell pour lancer la fonction et plus besoin de faire de bricolage. Comme expliqué #5.

Pour avoir la même chose que le #1 sans sous-shell

#!/bin/bash
a=1
fct() { a=2 ; b="ma fonction" ;}
fct
echo "a = $a // b = $b"

Dernière modification par Compte anonymisé (Le 05/12/2017, à 20:47)

#14 Le 05/12/2017, à 21:07

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Watael a écrit :

sans modification "permanente" de l'IFS :

IFS=$'\n' retour=( $(fct) )

avec la réserve que le retour de la fonction ne peut plus être sur plusieurs lignes, mais on peut toujours choisir un séparateur plus rare : µ.

Pardonne-moi, mais je ne saisis pas la différence...

Watael a écrit :

sur le même modèle, un peu plus lourd :

IFS=$'\n' read -d '' -r a retour < <(fct)

et moins problématique, car retour prend tout le reste.

J'ai essayé :

a=1
fct() { a=2 ; echo "$a le retour de ma fonction" ;}
read -d '' -r a b < <(fct)
echo "a = $a // b = $b"

Ça marche et ça semble être exactement ce que je recherchais.
Par contre ça vole largement au dessus de mon niveau.
Pourrais-tu m'expliquer tout ça ? Je ne maîtrise ni "read", ni la redirection " < <(...)". heu... c'est bien une redirection ?


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#15 Le 05/12/2017, à 21:12

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Anonyme68 a écrit :
#!/bin/bash
a=1
fct() { a=2 ; b="ma fonction" ;}
fct
echo "a = $a // b = $b"

Oui, forcément. Mais il faut prévoir tes variables quand tu écris de la fonction.
b=$(fct) permet de mettre directement le résultat dans une variable.


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#16 Le 05/12/2017, à 21:26

Watael

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

tiens !? je croyais que l'IFS n'était modifié, comme pour read, que pour l'assignation du tableau.
mais pas du tout :

$ IFS=$' \t\n'
$ od -c <<<"$IFS"
0000000      \t  \n  \n
0000004
$ IFS='x' read a b <<<"AxB"
$ echo $a $b
A B
$ od -c <<<"$IFS"
0000000      \t  \n  \n
0000004
$ 

mais non :

$ IFS=$' \t\n'
$ od -c <<<"$IFS"
0000000      \t  \n  \n
0000004
$ IFS='x' ar=( mlk poi) 
$ od -c <<<"$IFS"
0000000   x  \n
0000002
$ 

:/


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#17 Le 05/12/2017, à 22:46

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Watael,
J'ai essayé :

a=1
fct() { a=2 ; echo "$a le retour de ma fonction" ;}
read a b c < <(fct)
echo "a = $a // b = $b // c = $c"

$ ./mon_script
$ a = 2 // b = le // c = retour de ma fonction

Donc, si j'ai bien compris, grâce à read, je peux récupérer autant de variable que je veux de ma fonction sans avoir créer de sous-shell (puisque je n'utilise pas $(..)). C'est tout à fait intéressant.
Serait-il possible de tout mettre dans un tableau ?
Un truc du genre :

read ${tab[@]} < <(fct)
echo "a = ${tab[0]} // b = ${tab[1]} // c = ${tab[2]}"

Par contre il me semble que l'option -d '' de read définit un délimiteur, alors pourquoi ça n'a pas le même effet que l'IFS ? Et pourquoi l'IFS ne change pas quand il est suivit d'un read ?

$ read -d 'x' a b <<<"AxB"
$ echo $a $b
A
$ IFS="x" read a b <<<"AxB"
$ echo $a $b
A B

L'option -r' parait être utiliser pour oublier les caractères échappés avec \.
Le chevron < permet de redirigé l'entrée de read (par défaut le clavier).

Ceci dit, je ne comprends toujours pas la notation <(..) hmm
Je sais que ce n'est pas directement le sujet mais un peu d'aide serait la bienvenue.

Quant à <<<".." ce n'est pas évident de faire une recherche web là-dessus...

Dernière modification par arno_lupin (Le 05/12/2017, à 22:50)


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#18 Le 05/12/2017, à 22:48

pingouinux

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

@Watael #17 :
J'avais déjà vu ça, et m'étais aussi posé la question. J'ai l'impression que lorsqu'il n'y a que des assignations sur la ligne, la variable conserve sa valeur, mais pas si on a une "vraie" commande.

Hors ligne

#19 Le 05/12/2017, à 23:02

Watael

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

<(...) est une substitution de processus (c'est différent d'une substitution de commandes).
c'est un peu comme un pipe. ±

<<< est une chaîne-en-ligne (here-string), l'équivalent d'un document-en-ligne (here-doc) pour les chaînes.

tout cela est expliqué dans le (peu engageant) man bash, et détaillé dans le manuel de référence de bash

Dernière modification par Watael (Le 05/12/2017, à 23:05)


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#20 Le 05/12/2017, à 23:17

Zakhar

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

L'essentiel a été dit !

Il faut s'imaginer comment fonctionne l'appel d'un sous-shell. C'est un nouveau process qui est crée à partir du parent, fait ce qu'il a à faire, et se termine.

Le parent peut "passer" plein d'informations à ce sous-shell de plein de façons : paramètres (ligne de commande), environnement, pipe, etc...

Mais ensuite le process ainsi créé vit sa vie indépendamment du parent, ce qui est d'autant plus vrai qu'on peut même lancer des fils "détachés" (&).

Si le process fils n'est pas détaché, les seules "remontées" standard vers le parent sont :
- le code retour
- la sortie standard (stdout)

Si cela ne suffit pas, il faut créer des modes indépendants de communication : fichier, netcat, etc...

Bref en résumé :
parent ==> fils : plein de possibilité (initialisation)
fils ==> parent : très limité (sauf "contournements")

A noter cependant que les trucs du genre

myvar="$( commande arg1 arg2)"

Sont bien un sous-shell qui utilise la sortie standard pour récupérer l'information du "fils". C'est donc finalement un procédé assez courant même s'il est limité.

Dernière modification par Zakhar (Le 05/12/2017, à 23:20)


"A computer is like air conditioning: it becomes useless when you open windows." (Linus Torvald)

Hors ligne

#21 Le 05/12/2017, à 23:38

MicP

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

D'autres liens, au cas où…

arno_lupin a écrit :

la notation <(..)

Voir Process substitution dans : http://wiki.bash-hackers.org/syntax/exp … proc_subst

arno_lupin a écrit :

< <(..)

Voir Avoiding subshells  dans : http://wiki.bash-hackers.org/syntax/exp … proc_subst

arno_lupin a écrit :

<<<

Voir Here strings dans : http://wiki.bash-hackers.org/syntax/redirection

Hors ligne

#22 Le 05/12/2017, à 23:40

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

à Watael,
C'est vrai que le manuel n'est pas très engageant,

man bash a écrit :

The process list is run asynchronously, and its input or output appears as a filename. This filename is passed as an argument to the current command as the result of the expansion.
-- google trad
La liste de processus est exécutée de manière asynchrone et son entrée ou sortie apparaît sous la forme d'un nom de fichier. Ce nom de fichier est transmis en tant qu'argument à la commande en cours à la suite de l'expansion.

J'avais cru comprendre que <( ) remplaçait un nom de fichier et donc ce serait plutôt intéressant pour des commandes le nécessitant, par exemple mkvmerge
Mais

$ mkvmerge -o sortie.mkv --chapters <( CHAPTER01=00:00:00.000 CHAPTER01NAME=Début ) entree.mkv
Erreur : Impossible d'ouvrir « /dev/fd/63 » en lecture.

Qu'est-ce donc : « /dev/fd/63 » ?
Mes excuses, une fois de plus si je m'éloigne un peu du sujet


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#23 Le 05/12/2017, à 23:45

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Merci MicP pour la doc, je vais tenter d'éplucher ça.


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne

#24 Le 05/12/2017, à 23:49

MicP

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

arno_lupin a écrit :

Qu'est-ce donc : « /dev/fd/63 » ?

"http://wiki.bash-hackers.org/syntax/expansion/proc_subst" a écrit :

…a FIFO or a file in /dev/fd/…

Dernière modification par MicP (Le 05/12/2017, à 23:50)

Hors ligne

#25 Le 05/12/2017, à 23:51

arno_lupin

Re : [résolu] Portée des variables et appels de fonctions ... et sous-shell

Zakhar a écrit :

parent ==> fils : plein de possibilité (initialisation)
fils ==> parent : très limité (sauf "contournements")

J'ai bien compris que lorsque on veut avoir une bonne visibilité sur les variables il valait mieux éviter les sous-shells. Mais parfois c'est un peu difficile hmm


Ubuntu 20.04.1 LTS (Focal Fossa) 64-bit .. MATE 1.24.0

Hors ligne