[bash] Bug ou feature ?

14 réponses
Avatar
JKB
Bonjour à tous,

Je viens de passer quelques jours à pister un bug dans un script
shell pas compliqué du tout et j'aimerais savoir s'il s'agit d'une
fonctionnalité ou d'un bug (et si c'est une fonctionnalité
m'expliquer pourquoi).

#!/bin/bash

PATH=/bin:/sbin:/usr/bin:/usr/sbin
QUEUE=/home/machin/queue

for i in $QUEUE/*.to_be_sent
do
echo $i
done

exit 0

Trivial me direz vous. Lorsque la queue est vide, je ne devrais
obtenir aucune réponse. Raté, j'obtiens un superbe :

/home/machin/queue/*.to_be_sent

sur la sortie standard (et pas sur la sortie d'erreur, ce qui est
logique, /home/machin/queue/*.to_be_sent est le contenu de $i !).

En revanche, si je remplace

for i in $QUEUE/*.to_be_sent

par

for i in $(ls $QUEUE/*.to_be_sent 2> /dev/null)

ça fonctionne. D'où ma question : pourquoi dans le premier cas
l'expansion ne se fait-elle pas comme je l'attends ? Le bash utilisé
est celui de la distribution Debian/Stable i386.

Merci de vos lumières,

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr

10 réponses

1 2
Avatar
Jean-Marc Bourguet
JKB writes:

Bonjour à tous,

Je viens de passer quelques jours à pister un bug dans un script
shell pas compliqué du tout et j'aimerais savoir s'il s'agit d'une
fonctionnalité ou d'un bug (et si c'est une fonctionnalité
m'expliquer pourquoi).

#!/bin/bash

PATH=/bin:/sbin:/usr/bin:/usr/sbin
QUEUE=/home/machin/queue

for i in $QUEUE/*.to_be_sent
do
echo $i
done

exit 0

Trivial me direz vous. Lorsque la queue est vide, je ne devrais
obtenir aucune réponse. Raté, j'obtiens un superbe :




Feature. Voir shopt -s nullglob dans la doc de bash.

--
Jean-Marc
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Alain Ketterlin
JKB writes:

[...]
#!/bin/bash

PATH=/bin:/sbin:/usr/bin:/usr/sbin
QUEUE=/home/machin/queue

for i in $QUEUE/*.to_be_sent
do
echo $i
done

exit 0

Trivial me direz vous. Lorsque la queue est vide, je ne devrais
obtenir aucune réponse. Raté, j'obtiens un superbe :

/home/machin/queue/*.to_be_sent



C'est le comportement par défaut de bash (aucune idée si c'est
standard). Le man de bash dit :

Pathname Expansion
After word splitting, unless the -f option has been set, bash sc ans
each word for the characters *, ?, and [. If one of these charact ers
appears, then the word is regarded as a pattern, and replaced with an
alphabetically sorted list of file names matching the pattern. If no
matching file names are found, and the shell option nullglob is not
enabled, the word is left unchanged. If the nullglob option is s et,
and no matches are found, the word is removed. If the failglob sh ell
option is set, and no matches are found, an error message is prin ted
and the command is not executed. [...]

Si tu tiens à bash, alors nullglob est sûrement l'option que tu c herches.

-- Alain.
Avatar
JKB
Le Thu, 15 Mar 2012 10:27:08 +0100,
Alain Ketterlin écrivait :
JKB writes:

[...]
#!/bin/bash

PATH=/bin:/sbin:/usr/bin:/usr/sbin
QUEUE=/home/machin/queue

for i in $QUEUE/*.to_be_sent
do
echo $i
done

exit 0

Trivial me direz vous. Lorsque la queue est vide, je ne devrais
obtenir aucune réponse. Raté, j'obtiens un superbe :

/home/machin/queue/*.to_be_sent



C'est le comportement par défaut de bash (aucune idée si c'est
standard). Le man de bash dit :

Pathname Expansion
After word splitting, unless the -f option has been set, bash scans
each word for the characters *, ?, and [. If one of these characters
appears, then the word is regarded as a pattern, and replaced with an
alphabetically sorted list of file names matching the pattern. If no
matching file names are found, and the shell option nullglob is not
enabled, the word is left unchanged. If the nullglob option is set,
and no matches are found, the word is removed. If the failglob shell
option is set, and no matches are found, an error message is printed
and the command is not executed. [...]

Si tu tiens à bash, alors nullglob est sûrement l'option que tu cherches.



Merci pour ces infos. J'avais raté ça dans la doc de bash.

Cordialement,

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Tonton Th
On 03/15/2012 10:27 AM, Alain Ketterlin wrote:

Trivial me direz vous. Lorsque la queue est vide, je ne devrais
obtenir aucune réponse. Raté, j'obtiens un superbe :

/home/machin/queue/*.to_be_sent



C'est le comportement par défaut de bash (aucune idée si c'est
standard). Le man de bash dit :



Il me semble que le bug est dans le comportement
différent selon que stderr est redirigé ou pas.

--

Nous vivons dans un monde étrange/
http://foo.bar.quux.over-blog.com/
Avatar
Hugues
Hello,

Tu as eu ta réponse, par contre j'ai une remarque :


Ce cher JKB a posté :

for i in $(ls $QUEUE/*.to_be_sent 2> /dev/null)



ls sert à *formatter l'affichage*, et dépend énormément de
l'environnement utilisateur (LC_ALL, LC_DATE, etc..). Il ne doit en
aucun cas être utilisé pour du parsing !!

Si vraiment tu veux utiliser un outil de type "ls", utilise plutôt
"find" :

for i in $(find $QUEUE/ -name "*.to_be_sent" 2>/dev/null)


C'est bien plus propre.

Mes 2cts. ;)
--
Hugues Hiegel [http://www.hiegel.fr/~hugues/]
Avatar
JKB
Le Thu, 15 Mar 2012 11:20:46 +0100,
Hugues écrivait :

Hello,

Tu as eu ta réponse, par contre j'ai une remarque :


Ce cher JKB a posté :

for i in $(ls $QUEUE/*.to_be_sent 2> /dev/null)



ls sert à *formatter l'affichage*, et dépend énormément de
l'environnement utilisateur (LC_ALL, LC_DATE, etc..). Il ne doit en
aucun cas être utilisé pour du parsing !!



Oui mais non. La première chose que je fais dans un script, c'est
positionner la localisation. Quant à ls, il me semble qu'il prend
automatiquement l'option -1 dans ce cas.

Si vraiment tu veux utiliser un outil de type "ls", utilise plutôt
"find" :

for i in $(find $QUEUE/ -name "*.to_be_sent" 2>/dev/null)


C'est bien plus propre.



Certes.

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Alain Ketterlin
Tonton Th writes:

On 03/15/2012 10:27 AM, Alain Ketterlin wrote:

Trivial me direz vous. Lorsque la queue est vide, je ne devrais
obtenir aucune réponse. Raté, j'obtiens un superbe :

/home/machin/queue/*.to_be_sent



C'est le comportement par défaut de bash (aucune idée si c'est
standard). Le man de bash dit :



Il me semble que le bug est dans le comportement
différent selon que stderr est redirigé ou pas.



Je ne vois pas de quel bug tu parles. S'il n'y a pas de fichiers, c'est
ls qui fait le travail (n'affiche rien sinon un message d'erreur, qui
part sur /dev/null).

-- Alain.
Avatar
Gilles Pion
Ref: de Alain Ketterlin

C'est le comportement par défaut de bash (aucune idée si c'est
standard).



C'est standard au sens Posix en tout cas:

http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13_03

"If the pattern contains an invalid bracket expression or does not match any
existing filenames or pathnames, the pattern string shall be left unchanged."
--
Gilles Pion
Avatar
naddy
Gilles Pion wrote:

>C'est le comportement par défaut de bash (aucune idée si c'est
>standard).

C'est standard au sens Posix en tout cas:



C'est aussi le comportement historique :

| If no file name is found that matches the pattern then the word
| is left unchanged.

http://www.freebsd.org/cgi/man.cgi?query=sh&apropos=0&sektion=0&manpath=Unix+Seventh+Edition&archÞfault&format=html

--
Christian "naddy" Weisgerber
Avatar
Cyrille Lefevre
Le 15/03/2012 11:20, Hugues a écrit :

Si vraiment tu veux utiliser un outil de type "ls", utilise plutà ´t
"find" :

for i in $(find $QUEUE/ -name "*.to_be_sent" 2>/dev/null)

C'est bien plus propre.



Bonjour,

à la différence que find est récursif et pas ls, et malheu reusement,
il n'y a pas d'option portable pour limiter la récursivité tel que le
GNUisme -maxdepth 1

Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%
supprimer "%nospam% et ".invalid" pour me repondre.
1 2