2010-07-08 5 views
0

En essayant de créer une instruction conditionnelle pour vérifier le nombre de fichiers dans un répertoire, je suis tombé sur un problème. Ma première façon d'écrire ce script:Interprétation des commandes du shell dans les instructions Bash if/else

ELEM=`ls -l $DIR | wc -l` 
if [ $ELEM -lt 5 ] ; then 

fonctionne. Cependant, je veux déplacer mon $ ELEM dans le bloc de paramètres conditionnel afin qu'il puisse être interprété lorsque j'atteins cette instruction if. J'ai essayé de jouer avec différentes combinaisons de guillemets simples, de guillemets doubles, de coches de dos et de parenthèses.

Est-ce que quelqu'un sait comment résoudre ce problème?

+0

Où est le problème? Si cela ne fait aucune différence si vous comptez vos fichiers à l'extérieur ou à l'intérieur de l'instruction 'if'. – Philipp

Répondre

0

Pour une raison quelconque, il n'y a pas eu de moi jusqu'à ce que tout à l'heure d'utiliser ceci:

ELEM="`ls -l $DIR | wc -l`" 

Merci pour votre temps.

+0

Je ne suis pas sûr de savoir comment cela résout votre problème; l'expression est toujours évaluée à cette ligne, le résultat est juste cité –

+0

Y at-il de toute façon pour résoudre ce problème? – Melissa

+0

De plus, la citation incorrecte ('$ DIR') n'est pas indiquée. De plus, je ne vois pas du tout le problème: il est complètement équivalent que le comptage se fasse dans le cadre d'une affectation ou à l'intérieur d'un test. – Philipp

2

N'utilisez jamais ls en mode de traitement par lots, utilisez plutôt la globalisation. Evitez également les apostrophes inverses, non cotées variables, et la [ builtin:

shopt -s nullglob # expand to an empty array if directory is empty 
shopt -s dotglob # also glob dotfiles 
files=("$DIR"/*) 
count=${#files[@]} 
if ((count > 5)) 
then 
    ... 
fi 
+0

Pourquoi est-il mauvais d'utiliser 'ls' dans les scripts shell? Pourquoi dois-je éviter d'utiliser des coches de retour, des variables sans guillemets et des parenthèses? Je pensais que le globbing était principalement utilisé pour les manipulations de regex. – Melissa

+1

Voir http://mywiki.wooledge.org/BashPitfalls, http://mywiki.wooledge.org/BashFAQ/082, http://mywiki.wooledge.org/BashFAQ/031, http: //mywiki.wooledge. org/BashGuide/Patterns, http://mywiki.wooledge.org/BashGuide/Practices. La programmation de Bash a tellement de pièges que vous devriez vraiment lire toutes les pages du wiki de Greg concernant Bash avant d'écrire des scripts. – Philipp

+0

Merci pour votre aide. – Melissa

0

Ce que vous semblez vouloir être en mesure de faire quelque chose que C permet:

if (elem = countfiles(dir) < 5) 

Bash peut le faire comme ceci:

if (((elem = $(ls "$DIR" 2>/dev/null | wc -l)) < 5)) 

Ou vous pouvez créer une fonction appelée countfiles et l'utiliser comme ceci:

if (((elem = $(countfile "$DIR")) < 5)) 

où la fonction pourrait être quelque chose comme:

countfiles() { 
    find "$1" -maxdepth 1 -type f | wc -l 
} 
+0

La quatrième version ne fonctionnera pas sur les noms de fichiers contenant des retours à la ligne, et la seconde sera probablement nonportable sauf si le comportement de 'ls' w.r.t. les noms de fichiers avec newlines sont standardisés. Pourquoi appeler deux processus externes pour quelque chose que Bash peut faire sans aide extérieure? – Philipp

+0

@Philipp: Le but de ma réponse n'était pas de résoudre les problèmes d'utilisation inappropriée de 'ls 'ou d'autres pièges de Bash. Vous avez bien couvert ceux-ci dans votre commentaire joint à votre réponse. J'aurais dû faire référence à cela dans ma réponse pour plus de clarté. Le but de ma réponse était d'aborder la preuve que j'ai vu dans la question du PO et divers commentaires qu'il semblait y avoir un désir d'utiliser les effets secondaires de type C pour définir une variable et la tester en même temps. Parlant des noms de fichiers, [ceci] (http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html) est nécessaire à la lecture. –

0

La plupart des solutions sont affichées jusqu'à présent (à mon humble avis) overcomplicated. Tant que la commande ls sur votre système prend en charge l'option -B (affichage des caractères spéciaux comme des séquences d'échappement octal), vous pouvez simplement utiliser:

if [[ $(ls -B "$DIR" | wc -l) -lt 5 ]]; then 

Notez que lors de l'analyse ls est généralement une mauvaise idée, dans ce cas, tous les Nous essayons de trouver le nombre d'inscriptions, donc il y a beaucoup moins de choses à faire que d'habitude. En fait, la seule chose qui préoccupe wc -l est le nombre de lignes, donc la seule chose qui pourrait mal se passer est qu'un nom de fichier pourrait avoir une nouvelle ligne, et donc être confondu avec deux noms de fichiers; en utilisant l'option -B à ls protège contre cela, de sorte qu'il finit par être sûr (au moins aussi loin que je peux voir).

0

fonction countfiles améliorée (qui ne soit pas confondu par de nouvelles lignes dans les noms de fichiers):

countfiles() { 
    find "$1" -maxdepth 1 -type f -print0 | tr -dc '\0' | wc -c 
} 
Questions connexes