Rechercher récursivement des fichiers avec une extension spécifique

437

J'essaie de trouver tous les fichiers avec une extension spécifique dans un répertoire et ses sous-répertoires avec ma bash (dernière version Ubuntu LTS).

Voici ce qui est écrit dans un fichier script:

#!/bin/bash

directory="/home/flip/Desktop"
suffix="in"

browsefolders ()
  for i in "$1"/*; 
  do
    echo "dir :$directory"
    echo "filename: $i"
    #   echo ${i#*.}
    extension=`echo "$i" | cut -d'.' -f2`
    echo "Erweiterung $extension"
    if     [ -f "$i" ]; then        

        if [ $extension == $suffix ]; then
            echo "$i ends with $in"

        else
            echo "$i does NOT end with $in"
        fi
    elif [ -d "$i" ]; then  
    browsefolders "$i"
    fi
  done
}
browsefolders  "$directory"

Malheureusement, lorsque je démarre ce script dans le terminal, il dit:

[: 29: in: unexpected operator

(avec $extensionau lieu de 'in')

Que se passe-t-il ici, où est l'erreur? Mais cette accolade frisée

retourner
la source
2
L'erreur provient d'un '{'
manquant

Réponses:

750
find $directory -type f -name "*.in"

est un peu plus court que tout cela (et plus sûr - traite des espaces dans les noms de fichiers et les noms de répertoire).

Votre script échoue probablement pour les entrées qui n'ont pas .de nom, ce qui $extensionles rend vides.

Tapis
la source
16
oui, findest récursif par défaut. vous pouvez limiter les profondeurs si vous le souhaitez (voir la page de manuel).
Mat
1
Je voudrais passer tous les fichiers trouvés comme arguments dans un fichier jar. Comment cela peut-il être réalisé?
retournez
8
@flip: c'est une question différente. Postez une nouvelle question, détaillant exactement ce que vous aimeriez faire et ce que vous avez essayé jusqu'à présent.
Mat
Une petite correction: utilisez '* .in' ou \ *. In au lieu de "* .in" car les guillemets doubles n'empêchent pas l'expansion du shell. C'est-à-dire que votre script ne fonctionnera pas correctement s'il y a un fichier avec l'extension .in dans le répertoire courant.
Shnatsel
4
@Shnatsel: les guillemets doubles empêchent l'expansion du shell. Essaye le.
Mat
188
find {directory} -type f -name '*.extension'

Exemple: pour rechercher tous les csvfichiers du répertoire courant et de ses sous-répertoires, utilisez:

find . -type f -name '*.csv'
Mohammad AlQanneh
la source
60

La syntaxe que j'utilise est un peu différente de celle suggérée par @Matt:

find $directory -type f -name \*.in

(c'est une frappe de moins).

Scott C Wilson
la source
1
Le script de Matt ne fonctionnera pas non plus s'il y a un fichier avec l'extension .in dans le répertoire courant, alors que le vôtre fonctionnerait toujours. Voir stackoverflow.com/questions/5927369/…
Shnatsel
4
@Shnatsel ce commentaire (et donc le vôtre) est tout à fait faux.
gniourf_gniourf
1
@gniourf_gniourf Vous devez fournir une référence pour votre déclaration, sinon on pourrait simplement dire: "Non, vous vous trompez". Mais en fait, vous avez raison: gnu.org/software/bash/manual/html_node/Double-Quotes.html
Murmel
@ user1885518: Je pense que ce devrait être le gars qui prétend que le script ne fonctionne pas qui devrait fournir quelques exemples où le script échoue. C'est ce que je fais quand je laisse des commentaires où il y a des scripts cassés: il s'agit généralement de citations et de noms de fichiers contenant des espaces, des nouvelles lignes, des globes, etc., et j'explique spécifiquement pourquoi il est cassé.
gniourf_gniourf
2
Fournir des références est toujours un bon moyen dans une discussion, cela ne dépend pas de qui était le premier. Il devrait, vous devriez.
Murmel
14

Sans utiliser find:

du -a $directory | awk '{print $2}' | grep '\.in$'
rtrn
la source
3
Ce grepn'est pas vraiment nécessaire ici. awka des expressions régulières et pourrait limiter sa sortie à des valeurs correspondant à un modèle.
Kenster
Cette méthode est extrêmement utile si vous passez par des centaines de téraoctets. La commande de recherche prend trop de temps à traiter. Cela commence immédiatement.
Protonova
1
awk|grepest un anti-motif. Laissez awk faire le salut.
Jens
10
  1. Il {manque un aprèsbrowsefolders ()
  2. Tout $indevrait être$suffix
  3. La ligne avec cutvous n'obtient que la partie médiane de front.middle.extension. Vous devriez lire votre manuel shell ${varname%%pattern}et vos amis.

Je suppose que vous faites cela comme un exercice de script shell, sinon la findsolution déjà proposée est la voie à suivre.

Pour vérifier la syntaxe correcte du shell, sans exécuter de script, utilisez sh -n scriptname.

Jens
la source
10
find "$PWD" -type f -name "*.in"
kip2
la source
7

Bien que l'utilisation de la findcommande puisse être utile ici, le shell lui-même fournit des options pour répondre à cette exigence sans aucun outil tiers. Le bashshell fournit une option de prise en charge globale étendue à l'aide de laquelle vous pouvez obtenir les noms de fichiers sous des chemins récursifs qui correspondent aux extensions souhaitées.

L'option étendue est celle extglobqui doit être définie à l'aide de l' shoptoption ci-dessous. Les options sont activées avec le -ssupport et désactivées avec le -udrapeau. De plus, vous pouvez utiliser plusieurs options, c'est- nullglobà- dire dans lesquelles un glob inégalé est entièrement balayé, remplacé par un ensemble de zéro mot. Et globstarcela permet de récuser à travers tous les répertoires

shopt -s extglob nullglob globstar

Maintenant, tout ce que vous devez faire est de former l'expression glob pour inclure les fichiers d'une certaine extension que vous pouvez faire comme ci-dessous. Nous utilisons un tableau pour remplir les résultats globaux car lorsqu'ils sont correctement cités et développés, les noms de fichiers avec des caractères spéciaux restent intacts et ne sont pas cassés en raison de la séparation des mots par le shell.

Par exemple pour lister tous les *.csvfichiers dans les chemins récursifs

fileList=(**/*.csv)

L'option **est de récuser à travers les sous-dossiers et *.csvest une extension globale pour inclure n'importe quel fichier des extensions mentionnées. Maintenant, pour imprimer les fichiers réels, faites simplement

printf '%s\n' "${fileList[@]}"

Utiliser un tableau et faire une expansion entre guillemets appropriée est la bonne façon lorsqu'il est utilisé dans des scripts shell, mais pour une utilisation interactive, vous pouvez simplement utiliser lsavec l'expression glob comme

ls -1 -- **/*.csv

Cela pourrait très bien être étendu pour correspondre à plusieurs fichiers, c'est-à-dire un fichier se terminant par plusieurs extensions (c'est-à-dire similaire à l'ajout de plusieurs indicateurs dans la findcommande). Par exemple, considérez le cas où vous devez obtenir tous les fichiers image récursifs, c'est-à-dire les extensions *.gif, *.pnget *.jpgtout ce dont vous avez besoin est

ls -1 -- **/+(*.jpg|*.gif|*.png)

Cela pourrait très bien être étendu pour avoir également des résultats négatifs. Avec la même syntaxe, on pourrait utiliser les résultats du glob pour exclure des fichiers d'un certain type. Supposons que vous souhaitez exclure les noms de fichiers avec les extensions ci-dessus, vous pouvez le faire

excludeResults=()
excludeResults=(**/!(*.jpg|*.gif|*.png))
printf '%s\n' "${excludeResults[@]}"

La construction !()est une opération de négation qui n'inclut aucune des extensions de fichier répertoriées à l'intérieur et |est un opérateur d'alternance tout comme utilisé dans la bibliothèque des expressions régulières étendues pour effectuer une correspondance OU des globes.

Notez que cette prise en charge étendue de glob n'est pas disponible dans le shell POSIX bourne et son purement spécifique aux versions récentes de bash. Donc, si vous envisagez la portabilité des scripts exécutés sur POSIX et les bashshells, cette option ne serait pas la bonne.

Inian
la source
6

Pour rechercher tous les pom.xmlfichiers dans votre répertoire actuel et les imprimer, vous pouvez utiliser:

find . -name 'pom.xml' -print
Bharat Yadav
la source
1
find $directory -type f -name "*.in"|grep $substring
Sergiu
la source
0
for file in "${LOCATION_VAR}"/*.zip
do
  echo "$file"
done 
Avinash Kumar Mishra
la source
1
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant pourquoi et / ou comment ce code répond à la question améliore sa valeur à long terme.
rollstuhlfahrer