Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

(ba|pdk|z)sh & persistance des variables

18 réponses
Avatar
Pascal Cabaud
Bonsoir,

avec (pd)ksh (/bin/ksh de NetBSD), j'ai ca :
i=0
cat file | while read line
do
i=$(expr $i + 1)
done
echo "$i"
et j'obtiens... 0 !

Avec le ksh de Solaris 9 (ksh88 si je ne m'abuse), j'ai bien le nombre
de lignes dans file. La ou je commence a (encore) moins comprendre,
c'est que bash me fait pareil... tandis que zsh donne le resultat que
j'attends.

A cote de cela, le code suivant est evidemment ok avec bash, (pd)ksh et
zsh :
i=0
while (( $i < 10 ))
do
i=$(expr $i + 1)
done
echo $i

Ou est-ce que je peche ?

--
Pascal Cabaud

10 réponses

1 2
Avatar
Pascal Bourguignon
Pascal Cabaud writes:

Bonsoir,

avec (pd)ksh (/bin/ksh de NetBSD), j'ai ca :
i=0
cat file | while read line
do
i=$(expr $i + 1)
done
echo "$i"
et j'obtiens... 0 !

Avec le ksh de Solaris 9 (ksh88 si je ne m'abuse), j'ai bien le nombre
de lignes dans file. La ou je commence a (encore) moins comprendre,
c'est que bash me fait pareil... tandis que zsh donne le resultat que
j'attends.

A cote de cela, le code suivant est evidemment ok avec bash, (pd)ksh
et zsh :
i=0
while (( $i < 10 ))
do
i=$(expr $i + 1)
done
echo $i

Ou est-ce que je peche ?



Ton pêché est de croire que le shell est un langage de programmation.
Si tu veux calculer une somme fais le avec un vrai langage de programmation.
Par exemple:

#!/usr/bin/clisp -q -ansi
(with-open-file (file "file")
(print (loop for line = (read-line file nil nil) count 1)))

ou:

#!/usr/bin/clisp -q -ansi
(print (loop with i = 0 while (< i 10) do (incf i 1) finally (return i)))



Sinon, la raison pour laquelle ça ne marche pas en shell, c'est parce
qu'il fork des sous-processus quand tu utilise |, et que la variable i
est incrémentée dans le sous-processus, pas dans le script de haut-niveau.



--
__Pascal Bourguignon__ http://www.informatimago.com/

There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him. -- Robert Heinlein

Avatar
Jean-Louis Liagre
Pascal Bourguignon wrote:
Pascal Cabaud writes:

Bonsoir,

avec (pd)ksh (/bin/ksh de NetBSD), j'ai ca :
i=0
cat file | while read line
do
i=$(expr $i + 1)
done
echo "$i"
et j'obtiens... 0 !

Avec le ksh de Solaris 9 (ksh88 si je ne m'abuse), j'ai bien le nombre
de lignes dans file. La ou je commence a (encore) moins comprendre,
c'est que bash me fait pareil... tandis que zsh donne le resultat que
j'attends.

A cote de cela, le code suivant est evidemment ok avec bash, (pd)ksh
et zsh :
i=0
while (( $i < 10 ))
do
i=$(expr $i + 1)
done
echo $i

Ou est-ce que je peche ?


Ton pêché est de croire que le shell est un langage de programmation.


Non, ce problème est indépendant du langage de programmation, et je ne vois pas
pourquoi les shells ne mériteraient pas cette appellation.

Après un fork, une variable se retrouve séparée en deux entités indépendantes,
en shell, comme en C comme en tout langage supportant la création de nouveaux
processus.

Le vrai problème ici est le manque de cohérence entre les différents shells
quant au choix de la partie du pipeline à maintenir dans le shell courant.


Avatar
lhabert
Pascal Cabaud :

i=0
cat file | while read line
do
i=$(expr $i + 1)
done
echo "$i"
et j'obtiens... 0 !


Les deux process reliés par le pipe sont lancés dans deux sous-shells. Donc
les modifs de la variable i n'ont pas lieu dans le père...

Tu peux faire un :

i=0
cat file | {
while read line
do
i=$(expr $i + 1)
done
echo "$i"
}

pour y remédier. Enfin, pour ton cas particulier, tu peux aussi essayer un

while read line
do
i=$(expr $i + 1)
done < file

, j'ose espérer qu'aucun shell ne va forker pour ça. Quelqu'un connait par
coeur la norme?

Il y a cependant certains shells qui lancent la deuxième opérande du pipe
dans le même shell, ce qui explique que ton code marchait avec certains...

Avatar
lhabert
Pascal Bourguignon :

Ton pêché est de croire que le shell est un langage de programmation.


Pouet!

Avatar
Nicolas George
Luc Habert wrote in message <dth72m$15mo$:
while read line
do
i=$(expr $i + 1)
done < file

, j'ose espérer qu'aucun shell ne va forker pour ça. Quelqu'un connait par
coeur la norme?


Au pire, il y aurait :

exec 3<&1
exec 1<file
...
exec 1<&3
exec 3<&-

Avatar
Stephane Chazelas
On Wed, 22 Feb 2006 08:23:50 +0000 (UTC), Luc Habert wrote:
[...]
while read line
do
i=$(expr $i + 1)
done < file

, j'ose espérer qu'aucun shell ne va forker pour ça. Quelqu'un connait par
coeur la norme?


Le Bourne shell va forker. Les autres font des trucs louches,
comme duppliquer le file descriptor 0 (et mettre le CLOSE ON
EXEC dessus pour eviter de le passer a d'autres commandes) pour
pouvoir le restaurer apres.


POSIX dit que le Bourne shell n'est pas conforme.

--
Stephane

Avatar
Vincent Lefevre
Dans l'article <dth72m$15mo$,
Luc Habert écrit:

Il y a cependant certains shells qui lancent la deuxième opérande du
pipe dans le même shell, ce qui explique que ton code marchait avec
certains...


C'est ce que fait zsh pour cette raison. Dans zsh-users/4301:

zsh spawns a subshell for the LHS of a pipe, rather than
the RHS, which lets you do things like

$ do_something | read VAR

and have VAR still be set. [...]

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
bhamp0
C'est quoi l'intérêt de ce "script" pour faire un comptage de lignes
Pourquoi ne pas utiliser les commandes qui existent à la base (ici "w
-l")

--
bhamp0

Posted Via Usenet.com Premium Usenet Newsgroup Services
----------------------------------------------------------
** SPEED ** RETENTION ** COMPLETION ** ANONYMITY **
----------------------------------------------------------
http://www.usenet.com
Avatar
Pascal Cabaud
Pascal Bourguignon wrote:

Sinon, la raison pour laquelle ça ne marche pas en shell, c'est parce
qu'il fork des sous-processus quand tu utilise |, et que la variable i
est incrémentée dans le sous-processus, pas dans le script de haut-niveau.


Forcement, c'etait sous mon nez :-/

Merci bien !

--
Pascal Cabaud

Avatar
Pascal Cabaud
bhamp0 wrote:
C'est quoi l'intérêt de ce "script" pour faire un comptage de lignes ?
Pourquoi ne pas utiliser les commandes qui existent à la base (ici "wc
-l") ?


Je n'allais pas poster 300 lignes quand 5 suffisent ;-)

--
Pascal Cabaud

1 2