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 06/09/2016, à 17:22

Arbiel

[Résolu] Environnement d'exécution shell et sous-shell

N.B : j'avais initialement intitulé cette discussion "Bash : que fait la commande read ?", mais elle n'a en fait rien à voir avec cette fonction, d'où le changement d'intitulé. Je marque le problème résolu du fait des informations obtenues.

Bonjour à tous

Je ne comprends pas le fonctionnement de la commande read de bash.

Le manuel indique

"Bash Reference Manual a écrit :

read

              read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]

    One line is read from the standard input, or from the file descriptor fd supplied as an argument to the -u option, and the first word is assigned to the first name, the second word to the second name, and so on, with leftover words and their intervening separators assigned to the last name. If there are fewer words read from the input stream than names, the remaining names are assigned empty values. The characters in the value of the IFS variable are used to split the line into words. The backslash character ‘\’ may be used to remove any special meaning for the next character read and for line continuation. If no names are supplied, the line read is assigned to the variable REPLY.

J'ai écrit le petit script suivant

#!/bin/bash
shopt -s expand_aliases
source ~/.bash_aliases
e IFS
crypt_tab="/etc/crypttab";
code=victor-home
g -v "^[[:space:]]*(#|$)" "${crypt_tab}" | g "${code}"
g -v "^[[:space:]]*(#|$)" "${crypt_tab}" | g "${code}" | read  && e REPLY
g -v "^[[:space:]]*(#|$)" "${crypt_tab}" | g "${code}" | read dst src clef opts  && e dst src key opts

avec

remi@remi-Vostro-3550:~$ cat ~/.bash_aliases
alias s='sudo.sh '
alias mn="function man_info () { mkdir -p ${dirman:=$(mktemp -d --suffix=_info)} ; for commande in \${@}; do ! [ \${commande:0:1} = - ] && tmpi=${dirman}/\${commande}_info.txt && ! [ -e \${tmpi} ] && info \${commande} 1>\${tmpi} 2>/dev/null && chmod =400 \${tmpi} ; [ -s \${tmpi} ] && xdg-open \${tmpi}; done ; }; man_info "
alias e='function x { for y in "${@}"; do echo ${y}=\"${!y}\" ; done ; } ; x'
alias n='nautilus'
alias g='egrep'
remi@remi-Vostro-3550:~$ 

Le résultat est le suivant

remi@remi-Vostro-3550:~$ source '/home/remi/Bureau/read.sh' 
IFS=" "
victor-home UUID=37447a61-f946-4d38-a398-5a886c4e3f22 /dev/disk/by-uuid/4146dfad-26f0-4aec-99c3-8ab00c3e4297:/.victor-home:1 luks,keyscript=/lib/cryptsetup/scripts/passdev
REPLY=""
dst=""
src=""
key=""
opts=""
remi@remi-Vostro-3550:~$ 

où l'on voit que ni REPLY, ni les champs de la ligne sélectionnée ne sont initialisés comme on s'y attendrait.

Merci d'avance à quiconque m'indiquera l'erreur que j'ai faite.

Dernière modification par Arbiel (Le 07/09/2016, à 22:22)


Arbiel Perlacremaz
LDLC Aurore NK3S-8-S4 Ubuntu 20.04
Abandon d'azerty au profit de bépo, de google au profit de Lilo et de la messagerie électronique violable au profit de Protonmail, une messagerie chiffrée de poste de travail à poste de travail.

Hors ligne

#2 Le 06/09/2016, à 17:51

Watael

Re : [Résolu] Environnement d'exécution shell et sous-shell

salut,

deux choses :
- l'utilisation d'une variable requiert que son nom soit précédé par le signe dollar, sinon c'est une chaîne !
- une conduite (introduite par un caractère |) crée un sous-interpréteur; les variables qui y sont assignées n'existent pas ailleurs.
tu peux ajouter une option lastpipe (attention, dans la console, il faut désactiver le contrôle des tâches),
ou mettre les commandes dans une liste

$ echo bla | { read ; echo "$REPLY";}
bla

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

En ligne

#3 Le 06/09/2016, à 18:07

pingouinux

Re : [Résolu] Environnement d'exécution shell et sous-shell

Bonjour,
Avec ton alias e, le $ devant les variables n'est pas nécessaire, mais le regroupement indiqué par Watael l'est.

g "$code" <<<"$txt" | { read  && e REPLY; }

Hors ligne

#4 Le 07/09/2016, à 01:05

Arbiel

Re : [Résolu] Environnement d'exécution shell et sous-shell

@ Watael et pingouinux

Merci pour votre aide, qui résout le problème.

J'aurais pu m'en tenir là, mais après avoir relu le manuel de référence, il me reste des doutes et des demandes de confirmation de ce que j'ai compris.

1) 

paragraphe 3.7.4 a écrit :

When a program is invoked it is given an array of strings called the environment. … On invocation, the shell scans its own environment and creates a parameter for each name found, automatically marking it for export to child processes. Executed commands inherit the environment. … If the value of a parameter in the environment is modified, the new value becomes part of the environment, replacing the old. The environment inherited by any executed command consists of the shell's initial environment, whose values may be modified in the shell.

Je comprends dans ce texte (the shell scans its own environment and creates a parameter for each name found, automatically marking it for export to child processes) que chaque instruction d'affectation d'une nouvelle variable se traduit par la modification de l'environnement et que (whose values may be modified in the shell) la modification dont il est ici question peut entre autres résulter de la commande en question, comme par exemple d'une instruction d'affectation.

2)

paragraphe 3.2.2 a écrit :

Each command in a pipeline is executed in its own subshell

C'est ce que Watael m'a indiqué. Ainsi, dans ma commande

g -v "^[[:space:]]*(#|$)" "${crypt_tab}" | g "${code}" | read dst src clef opts  && e dst src key opts

les variables dst, src, clef et opts créées dans l'environnement d'exécution de read ne "remontent" pas dans l'environnement appelant et ne peuvent pas être transmises dans l'environnement d'exécution de l'alias e, où de nouvelles variables de même nom sont créées et initialisées à une valeur vide.

3)

paragraphe 3.7.3 a écrit :

When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following. Unless otherwise noted, the values are inherited from the shell.

    the shell's open files, plus any modifications and additions specified by redirections to the command
    the current working directory
    the file creation mode mask
    shell variables and functions marked for export, along with variables exported for the command, passed in the environment (see Environment)
    traps caught by the shell are reset to the values inherited from the shell's parent, and traps ignored by the shell are ignored

Apparemment ce ne sont pas les seules conduites qui s'exécutent dans leur propre environnement, mais toute commande autre qu'une fonction intégrée ou programmée. Et comme read est une fonction intégrée

remi@remi-Vostro-3550:~$ crypt_tab="/etc/crypttab"; code=victor-home; read dst src clef opts <<< $(g -v "^[[:space:]]*(#|$)" "${crypt_tab}" | g "${code}" ); e dst src clef opts;
dst="victor-home"
src="UUID=37447a61-f946-4d38-a398-5a886c4e3f22"
clef="/dev/disk/by-uuid/4146dfad-26f0-4aec-99c3-8ab00c3e4297:/.victor-home:1"
opts="luks,keyscript=/lib/cryptsetup/scripts/passdev"
remi@remi-Vostro-3550:~$ 

read crée et initilise les variables dans l'environnement du shell, comme le fait la mise entre accolades que vous m'avez indiquée.

4) J'ai alors voulu créer mes variables dans l'environnement appelant pour éviter leur création dans l'environnement de read, d'abord par des instructions d'affectation

remi@remi-Vostro-3550:~$ dst=; src=; clef=; opts=; crypt_tab="/etc/crypttab"; code=victor-home;  g -v "^[[:space:]]*(#|$)" "${crypt_tab}" | g "${code}" | read dst src clef opts && e dst src clef opts;
dst=""
src=""
clef=""
opts=""
remi@remi-Vostro-3550:~$ 

puis par la commande "declare -x" :

remi@remi-Vostro-3550:~$ declare -x dst src clef opts; crypt_tab="/etc/crypttab"; code=victor-home;  g -v "^[[:space:]]*(#|$)" "${crypt_tab}" | g "${code}" | read dst src clef opts && e dst src clef opts;
dst=""
src=""
clef=""
opts=""
remi@remi-Vostro-3550:~$ 

sans résultat.
L'environnement d'exécution de read et celui de e devraient hériter des variables préalablement créées dans l'environnement appelant, et les modifications apportées par read reportées dans cet environnement appelant et donc devraient être accessibles à e. Je ne vois pas du tout pourquoi ces instructions ne me donnent pas ce que j'attends.

5) l'insertion du read dans une boucle while initialise correctement mes variables

crypt_tab="/etc/crypttab"; code=victor-home; g -v "^[[:space:]]*(#|$)" "${crypt_tab}" | g "${code}" | while read dst src clef opts ; do e dst src clef opts; done;
dst="victor-home"
src="UUID=37447a61-f946-4d38-a398-5a886c4e3f22"
clef="/dev/disk/by-uuid/4146dfad-26f0-4aec-99c3-8ab00c3e4297:/.victor-home:1"
opts="luks,keyscript=/lib/cryptsetup/scripts/passdev"
remi@remi-Vostro-3550:~$

Faut-il en conclure que la conduite s'arrête sur l'instruction while et que le read qui suit s'exécute dans l'environnement appelant ?

Merci d'avance si vous pouvez éclairer ma lanterne.

Arbiel


Arbiel Perlacremaz
LDLC Aurore NK3S-8-S4 Ubuntu 20.04
Abandon d'azerty au profit de bépo, de google au profit de Lilo et de la messagerie électronique violable au profit de Protonmail, une messagerie chiffrée de poste de travail à poste de travail.

Hors ligne

#5 Le 07/09/2016, à 07:22

pingouinux

Re : [Résolu] Environnement d'exécution shell et sous-shell

1) et 2) Voici un exemple. On voit que seule une variable exportée est transmise à un sous-shell, et aucune variable modifiée dans le sous-shell ne remonte.

$ cat x
var1="variable_1"; export var2="variable_2"
echo
echo "Dans x, avant bash y (y est execute dans un sous-shell) : var1=$var1; var2=$var2"
bash y
echo "Dans x, apres bash y : var1=$var1; var2=$var2"
echo
echo "Dans x, avant source y (y est execute dans le shell courant) : var1=$var1; var2=$var2"
source y
echo "Dans x, apres source y : var1=$var1; var2=$var2"
echo
$ cat y
echo "Dans y, avant modif variables : var1=$var1; var2=$var2"
var1="var1_modifie"
var2="var2_modifie"
echo "Dans y, apres modif variables : var1=$var1; var2=$var2"
$ bash x

Dans x, avant bash y (y est execute dans un sous-shell) : var1=variable_1; var2=variable_2
Dans y, avant modif variables : var1=; var2=variable_2
Dans y, apres modif variables : var1=var1_modifie; var2=var2_modifie
Dans x, apres bash y : var1=variable_1; var2=variable_2

Dans x, avant source y (y est execute dans le shell courant) : var1=variable_1; var2=variable_2
Dans y, avant modif variables : var1=variable_1; var2=variable_2
Dans y, apres modif variables : var1=var1_modifie; var2=var2_modifie
Dans x, apres source y : var1=var1_modifie; var2=var2_modifie

3) Les variables sont créées dans le shell courant, on les voit.

4) Les variables sont créées dans un sous-shell, on ne les voit pas.

5)

..... | g "${code}" | while read dst src clef opts ; do e dst src clef opts; done;

C'est tout l'ensemble while read; do ...; done qui est exécuté dans le même sous-shell, où on crée et liste les variables.

Hors ligne

#6 Le 07/09/2016, à 22:18

Arbiel

Re : [Résolu] Environnement d'exécution shell et sous-shell

Bonsoir

Je te remercie.

Je vois un peu mieux ce qu'il en est. Cette gestion de l'environnement d'exécution du bash me semble un peu compliquée, ou plutôt, je ne vois pas bien l'intérêt de créer autant d'environnements successifs au cours du traitement d'un script. Mais je suppose que cette manière de faire comporte des avantages ou apporte des fonctions que je ne parviens pas à distinguer.

Arbiel


Arbiel Perlacremaz
LDLC Aurore NK3S-8-S4 Ubuntu 20.04
Abandon d'azerty au profit de bépo, de google au profit de Lilo et de la messagerie électronique violable au profit de Protonmail, une messagerie chiffrée de poste de travail à poste de travail.

Hors ligne