Éviter les erreurs dues à un astérisque non développé

16

En bash, j'utilise souvent des boucles for telles que les suivantes

for file in *.type; do 
  sommecommand "$file"; 
done;

pour effectuer une opération pour tous les fichiers correspondants *.type. Si aucun fichier avec cette fin n'est trouvé dans les répertoires de travail, l'astérisque n'est pas développé et j'obtiens généralement un message d'erreur indiquant qu'une commande n'a pas trouvé le fichier. Je peux immédiatement penser à plusieurs façons d'éviter cette erreur. Mais l'ajout d'un conditionnel ne semble pas très élégant. Existe-t-il un moyen court et propre d'y parvenir?

highsciguy
la source

Réponses:

20

Oui, exécutez la commande suivante:

shopt -s nullglob

cela annulera la correspondance et aucune erreur ne sera déclenchée.

  • si vous voulez ce comportement par défaut, ajoutez la commande dans votre ~/.bashrc
  • si vous voulez détecter un glob nul dans le shell POSIX, essayez

    for i in *.txt; do
      [ "$i" = '*.txt' ] && [ ! -e '*.txt' ] && continue
    done

Voir http://mywiki.wooledge.org/NullGlob

Gilles Quenot
la source
1
Notez qu'il est en fait possible d'avoir un fichier appelé *.txt. Il vaudrait la peine de vérifier si le fichier existe.
Chris Down
poste modifié en conséquence.
Gilles Quenot
@ChrisDown Notez que le même commentaire que sur votre réponse s'applique ici (avec des conséquences potentiellement plus graves à cause de la breakplace de continue).
Stéphane Chazelas
6

En bash, vous pouvez utiliser shopt -s nullglobpour développer un tableau vide s'il n'y a pas de correspondance.

Dans les shells POSIX sans nullglob, vous pouvez éviter ce problème en vérifiant que le nom de fichier transmis existe réellement en ayant [ -e "$file" ] || [ -L "$file" ] || continuecomme première partie de votre forboucle.

Chris Down
la source
1
Notez qu'il ne serait pas strictement équivalent car [ -eretournerait false pour les fichiers inaccessibles ou les fichiers qui sont des liens symboliques vers des fichiers inaccessibles ou inexistants.
Stéphane Chazelas
@StephaneChazelas, que les points sur les liens symboliques soient reconnus. Mais à quoi pensez-vous par "fichiers inaccessibles"? Même si moi chmod 0 the_file, [ -e the_file ]j'évalue toujours vrai, cela doit donc être autre chose.
dubiousjim
1
modification soumise pour gérer les liens symboliques brisés. j'espère que ça va.
dubiousjim
2
@dubiousjim, mkdir -p x/{a,b} && chmod 444 x && echo x/* && [ -e x/a ]. x / a est inaccessible mais comme x est lisible, x / * se développera.
Stéphane Chazelas
@StephaneChazelas, super, merci pour l'explication.
dubiousjim
4

La technique habituelle pour les obus qui n'ont pas d' nullgloboption est

set -- [*].type *.type
case $1$2 in
  '[*].type*.type') shift 2;;
  *) shift
esac
for file do
  cmd  -- "$file"
done

L'extra [*].typeest de couvrir le cas où il y a un fichier appelé *.typedans le répertoire courant.

Maintenant, si vous souhaitez inclure des fichiers dot, cela devient plus compliqué .

Je crois que cette technique a été inventée par Laura Fairhead sur Usenet il y a quelques années.

Stéphane Chazelas
la source
0

find . -name '*.type' -maxdepth 0 -exec somecommand "{}" ";"

Cela supprime forentièrement la boucle et le globbing du shell de l'équation. findexécutera la -execcommande une fois par correspondance, et s'il n'y a aucune correspondance, elle ne sera jamais exécutée. Les -maxdepth 0instructions recherchent de ne pas récursivement dans les sous-répertoires de l'argument de chemin nommé ( ., dans ce cas).

L'inconvénient est qu'il s'agit d'une autre application, bien que celle-ci soit présente sur pratiquement tous les systèmes Linux (et probablement sur la plupart des Unix également).

un CVn
la source