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

[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

4 réponses

1 2
Avatar
Cyrille Lefevre
Le 15/03/2012 10:10, JKB a écrit :
Bonjour,

#!/bin/bash

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

for i in $QUEUE/*.to_be_sent
do


# marche qqsoit le shell
case $i in *'*'*) break ;; esac
echo $i
done

exit 0



alternative qui ne marche pas si $QUEUE contient des espaces :

pattern=$QUEUE/*.to_be_sent
liste=$(echo $pattern)
case $liste in "$pattern") exit ;; esac
# ou
# [[ -n $BASH_VERSION ]] && shopt -s extglob
# [[ $liste = "$pattern ]] && exit
for i in $liste; do echo $i; done

autre alternative qui devrait fonctionner avec des blancs dans $QUEUE :

pattern=$QUEUE/*.to_be_sent
set -- $pattern
# ou
# set x $pattern
# shift
case $* in "$pattern") exit ;; esac
# ou
# [[ -n $BASH_VERSION ]] && shopt -s extglob
# [[ $* = "$pattern ]] && exit
for i; do echo $i; done

pour le reste, les explications ont déjà été donné es...

Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%
supprimer "%nospam% et ".invalid" pour me repondre.
Avatar
Hugues
Ce cher Cyrille Lefevre <cyrille.lefevre-news% a posté :

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 malheureusement,
il n'y a pas d'option portable pour limiter la récursivité tel que le
GNUisme -maxdepth 1



Et ! -iwholepath "*/*" ?


--
Hugues Hiegel [http://www.hiegel.fr/~hugues/]
Avatar
Gilles Pion
Ref: <jk0jmg$1gsc$ de 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 malheureusement,
il n'y a pas d'option portable pour limiter la récursivité tel que le
GNUisme -maxdepth 1



Une solution tordue mais portable ("-prune" est Posix)

find $QUEUE/. ( -type d ! -name '.' -prune ) -o -name "*.to_be_sent" -print

(le "/." et le "-print" sont importants pour que cela fonctionne)
--
Gilles Pion
Avatar
Gilles Pion
Ref: de Gilles Pion
Une solution tordue mais portable ("-prune" est Posix)

find $QUEUE/. ( -type d ! -name '.' -prune ) -o -name "*.to_be_sent" -print




je me rend compte que les parenthèses ne sont pas nécessaires ici, donc, en plus
simple!

find $QUEUE/. -type d ! -name '.' -prune -o -name "*.to_be_sent" -print
--
Gilles Pion
1 2