Parcourez tous les fichiers avec une extension spécifique

109
for i in $(ls);do
    if [ $i = '*.java' ];then
        echo "I do something with the file $i"
    fi
done

Je souhaite parcourir chaque fichier du dossier actuel et vérifier s'il correspond à une extension spécifique. Le code ci-dessus ne fonctionne pas, savez-vous pourquoi?

AR89
la source
4
Et quoi for i in $(ls *.java); do echo "do something with file $i"; done?
speakr
il n'y a aucun moyen de résoudre cette déclaration if?
AR89
1
Vous comparez $ià la chaîne littérale "* .java"; l'expansion du motif n'est pas effectuée ici.
chepner
Pour corriger l'instruction if telle que vous l'avez, utilisez if [[ $i == *.java ]]; then.. (notez les doubles [[]] et les * .java sans guillemets).
cet autre gars
2
Ne pas analyserls - accepter la réponse de @ chepner
glenn jackman

Réponses:

201

Aucun truc de fantaisie nécessaire:

for i in *.java; do
    [ -f "$i" ] || break
    ...
done

Le garde garantit que s'il n'y a pas de fichiers correspondants, la boucle se terminera sans essayer de traiter un nom de fichier inexistant *.java. Dans bash(ou les shells prenant en charge quelque chose de similaire), vous pouvez utiliser l' nullgloboption pour simplement ignorer une correspondance échouée et ne pas entrer dans le corps de la boucle.

shopt -s nullglob
for i in *.java; do
    ...
done
chepner
la source
5
La façon la plus simple est d'ajouter un autre motif: for i in *.java *.cpp; do. Si vous avez activé les modèles étendus bashavec shopt -s extglob, vous pouvez écrire for i in *.@(java|cpp); do.
chepner
8
Ce sera le cas s'il correspond à des fichiers. Vous devez utiliser shopt -s nullglobpour qu'un modèle non correspondant se développe en séquence vide plutôt que d'être traité littéralement.
chepner
1
@zygimantus oui ça devrait, tant que le répertoire courant est l'endroit où le script s'exécute. Si vous n'êtes pas dans le répertoire que vous souhaitez cependant, vous devriez cdaller dans ce répertoire avant de démarrer la forboucle
danielsdesk
1
@puk Cela dépend des options de votre shell. Par défaut, un modèle non correspondant est traité comme une chaîne littérale. Vous pouvez définir nullglobpour qu'elle soit traitée comme une séquence vide, ou failglobpour qu'elle soit traitée comme une erreur. (Si vous définissez les deux, failgloba priorité.)
chepner
3
@chepner Il peut être utile pour les non-experts d'indiquer cela dans la réponse car quelqu'un peut copier-coller et trouver que cela ne fonctionne pas. Un exemple parfait serait quelqu'un qui convertit tous les fichiers " .jpg" en " .png" avant d'effectuer une fonction cruciale
puk
13

la bonne réponse est @ chepner

EXT=java
for i in *.${EXT}; do
    ...
done

cependant, voici une petite astuce pour vérifier si un nom de fichier a une extension donnée:

EXT=java
for i in *; do
    if [ "${i}" != "${i%.${EXT}}" ];then
        echo "I do something with the file $i"
    fi
done
umläute
la source
comment serait-il avec une variable extau lieu de .java?
AR89
13

Ajouter récursivement des sous-dossiers,

for i in `find . -name "*.java" -type f`; do
    echo "$i"
done
Luismartingil
la source
au lieu de find . -name "*.java" -type f -exec echo \{\} \; pour éviter une mauvaise analyse de la sortie defind
umläute
1
Et si vous ne le faites pas, vous devriez au moins citer "$i"à l'intérieur de la boucle.
tripleee
2
Cela ne fonctionnera pas si l'un des fichiers a un espace dans son nom.
codeforester
1
@codeforester J'ai eu exactement ce problème et je l'ai résolu en utilisant la méthode de cette réponse: askubuntu.com/a/343753/551184
fsinisi90
7

Boucle à travers tous les fichiers se terminant par: .img, .bin, .txtsuffixe et imprimer le nom du fichier:

for i in *.img *.bin *.txt;
do
  echo "$i"
done

Ou de manière récursive (à retrouver également dans tous les sous-répertoires):

for i in `find . -type f -name "*.img" -o -name "*.bin" -o -name "*.txt"`;
do
  echo "$i"
done
Benny
la source
3

Je suis d'accord avec les autres réponses concernant la manière correcte de parcourir les fichiers. Cependant, le PO a demandé:

Le code ci-dessus ne fonctionne pas, savez-vous pourquoi?

Oui!

Un excellent article Quelle est la différence entre test, [et [[?] Explique en détail que parmi d'autres différences, vous ne pouvez pas utiliser expression matchingou pattern matchingdans la testcommande (qui est un raccourci pour [)

Nouveau test de fonctionnalité [[ancien test [Exemple

Correspondance de motif = (ou ==) (non disponible) [[$ name = a *]] || echo "le nom ne commence pas par un 'a': $ nom"

Expression régulière = ~ (non disponible) [[$ (date) = ~ ^ Ven \ ... \ 13]] && echo "C'est vendredi 13!"
correspondant à

C'est donc la raison pour laquelle votre script échoue. Si l'OP est intéressé par une réponse avec la [[syntaxe (qui a l'inconvénient de ne pas être supportée sur autant de plates-formes que la [commande), je serais heureux de modifier ma réponse pour l'inclure.

EDIT: Toutes les astuces sur la façon de formater les données dans la réponse sous forme de tableau seraient utiles!

user000001
la source
2

comme @chepner le dit dans son commentaire, vous comparez $ i à une chaîne fixe.

Pour développer et rectifier la situation, vous devez utiliser [[]] avec l'opérateur regex = ~

par exemple:

for i in $(ls);do
    if [[ $i =~ .*\.java$ ]];then
        echo "I want to do something with the file $i"
    fi
done

l'expression régulière à droite de = ~ est testée par rapport à la valeur de l'opérateur de gauche et ne doit pas être entre guillemets, (les guillemets n'entraîneront pas d'erreur mais se compareront à une chaîne fixe et échoueront donc très probablement "

mais la réponse de @chepner ci-dessus en utilisant glob est un mécanisme beaucoup plus efficace.

pétéchies
la source
comment serait-il avec une variable extau lieu de .java?
AR89
1
ack, pas besoin d'expression régulière: if [[ $i == *.java ]]ou if [[ $i == *.$ext ]]. But don't parse ls
Glenn Jackman
1

J'ai trouvé cette solution très pratique. Il utilise l' -oroption dans find:

find . -name \*.tex -or -name "*.png" -or -name "*.pdf"

Il trouvera les fichiers avec l' extension tex, pnget pdf.

f0nzie
la source