Motif `find -name` qui correspond à plusieurs motifs


335

J'essayais d'obtenir une liste de tous les fichiers python et html dans un répertoire avec la commande find Documents -name "*.{py,html}".

Puis vint la page de manuel:

Les accolades dans le modèle ('{}') ne sont pas considérées comme spéciales (c'est-à-dire que find. -Name 'foo {1,2}' correspond à un fichier nommé foo {1,2}, pas aux fichiers foo1 et foo2.

Comme cela fait partie d'une chaîne de tuyaux, j'aimerais pouvoir spécifier les extensions auxquelles il correspond au moment de l'exécution (pas de codage en dur). Si trouver ne peut tout simplement pas le faire, un Perl one-liner (ou similaire) serait bien.

Edit: La réponse que j'ai finalement trouvée inclut toutes sortes de conneries, et est un peu longue également, donc je l'ai postée en réponse à la démangeaison originale que j'essayais de gratter. N'hésitez pas à pirater cela si vous avez de meilleures solutions.



Un utilitaire souvent négligé et sous-utilisé est également locate, mais avec la mise en garde que la mise à jour interneb peut ne pas être à jour. Mais c'est rapide.
michael

Je vote pour fermer cette question comme hors sujet car elle appartient à Unix et Linux
Dan Dascalescu

Réponses:


481

Utilisation -o, ce qui signifie "ou":

find Documents \( -name "*.py" -o -name "*.html" \)

Vous auriez besoin de construire cette ligne de commande par programme, ce qui n'est pas si simple.

Utilisez-vous bash (ou Cygwin sous Windows)? Si vous l'êtes, vous devriez pouvoir faire ceci:

ls **/*.py **/*.html

qui pourrait être plus facile à construire par programme.


3
J'utilise zsh, qui, en règle générale, prend en charge tous les bashismes, et plus encore.
Xiong Chiamiov le

12
Zsh prend en charge la **recherche récursive; Bash ne le prend en charge que dans les versions 4.0 et supérieures, et uniquement avec shopt -s globstar.
éphémère

2
Combien d'arguments -o pouvez-vous avoir? J'ai une liste potentiellement longue de fichiers .gcda (données de couverture) à construire
Jasper Blues

40
Vous devez entourer les deux -names de supports, si vous utilisez -exec. Par exemplefind Documents \( -name "*.py" -o -name "*.html" \) -exec file {} \;
artbristol

2
Le commentaire @artbristol est très pertinent si, par exemple, vous ajoutez un -print0pour gérer les noms de fichiers avec des espaces.
nimrodm

63

Certaines éditions de find, principalement sur les systèmes linux, éventuellement sur d'autres prennent également en charge les options -regex et -regextype, qui trouvent des fichiers avec des noms correspondant à l'expression régulière.

par exemple

find . -regextype posix-egrep -regex ".*\.(py|html)$" 

devrait faire l'affaire dans l'exemple ci-dessus. Cependant, ce n'est pas une fonction de recherche POSIX standard et dépend de l'implémentation.


1
intéressant mais plus complexe que les autres réponses
m1k3y3

12
Plus simple: find . -regex ".*\.\(py\|html\)$"cela fonctionne parce que trouver par défaut les expressions régulières de style Emacs, qui sont légèrement différentes, vous n'avez donc pas besoin de spécifier le regextype.
robru

2
Si vous avez plusieurs expressions, -regextype posix-egrepc'est pratique (sinon vous devrez échapper à beaucoup de caractères). Il s'agit de la commande find que j'ai utilisée pour créer un crochet de distribution en créant un zip de distribution Windows (trouve les fichiers à modifier et les modifie dans le fichier en dos-eol): find -regextype posix-egrep -regex ".*(\.([chyl]|def|cpy|cob|conf|cfg)|(README|ChangeLog|AUTHORS|ABOUT-NLS|NEWS|THANKS|TODO|COPYING.*))$" -exec sed -i -e 's/\r*$/\r/' {} \;
Simon Sobisch

32

Vous pouvez ajouter par programme plus de -nameclauses, séparées par -or:

find Documents \( -name "*.py" -or -name "*.html" \)

Ou optez plutôt pour une boucle simple:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done

@ user2284570: alors soit il n'y a pas de *.pyfichiers ou vous avez une version bizarre de find. La commande ci-dessus fonctionne très bien.
Stephan202

Non, j'utilise -iname. Il ne retourne les *.pyfichiers que s'il les écrit dans la dernière position ( iname *.htmlla première expression aussi) . J'utilise la commande sur Debian.
user2284570

Utilisez-vous des citations? C'est très important.
Stephan202

1
Est-ce un -ou un -o?
Stephane

1
@StephaneEybert: soit c'est bien, mais seul ce dernier est compatible POSIX (selon la page de manuel).
Stephan202

16

Cela trouvera tous les fichiers .c ou .cpp sur linux

$ find . -name "*.c" -o -name "*.cpp"

Vous n'avez pas besoin de la parenthèse d'échappement sauf si vous effectuez des mods supplémentaires. Ici, à partir de la page de manuel, ils disent si le motif correspond, imprimez-le. Peut-être essaient-ils de contrôler l'impression. Dans ce cas, le -print agit comme un conditionnel et devient un conditionnel "ET". Cela empêchera tout fichier .c d'être imprimé.

$ find .  -name "*.c" -o -name "*.cpp"  -print

Mais si vous aimez la réponse originale, vous pouvez contrôler l'impression. Cela trouvera également tous les fichiers .c.

$ find . \( -name "*.c" -o -name "*.cpp" \) -print

Un dernier exemple pour tous les fichiers source c / c ++

$ find . \( -name "*.c" -o -name "*.cpp"  -o -name "*.h" -o -name "*.hpp" \) -print

11

J'avais un besoin similaire. Cela a fonctionné pour moi:

find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print

3
Parfait. Mais je trouve un peu étrange que cela ne fonctionne pas sans()
pedrofurla

Je voulais trouver des fichiers qui correspondent * .c * .cpp ou * .cc Avec seulement deux modèles -name Je n'ai pas besoin parens mais avec trois modèles -name jointes avec deux motifs -o find -name "*.cpp" -o -name "*.c" -o -name "*.cc" -print0je devais utiliser une paire de parens regrouper le second ou opérateur. find -name "*.cpp" -o \( -name "*.c" -o -name "*.cc" \) -print0Il se peut que -print0, qui est toujours "vrai", ait affecté la logique.
Cardiff Space Man

5

Mon défaut a été:

find -type f | egrep -i "*.java|*.css|*.cs|*.sql"

Comme l' findexécution moins intensive du processus par Brendan Long et Stephan202 et al.:

find Documents \( -name "*.py" -or -name "*.html" \)


3
ce n'est pas une utilisation correcte de egrepregexp, plutôt, vous avez un glob de shell où une regexp doit être utilisée. (En outre, l' findutilisation typique est find {directory} [options...] [action]:, où, selon impl, directorypeut être par défaut .et par actiondéfaut -print, mais je serai explicite.) Donc, utilisez plutôt quelque chose comme: find . -type f -print | egrep -i '\.java$|\.css$|\.cs$|\.sql$' Mais aussi, comme alternative très rapide à find, on pourrait aussi essayez located'une manière similaire (bien que pas nécessairement à jour, car il interroge une base de données interne pour une liste de fichiers)
michael

2
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done

simple mais fonctionne :)


1

J'avais besoin de supprimer tous les fichiers des répertoires enfants, à l'exception de certains fichiers. Les éléments suivants ont fonctionné pour moi (trois modèles spécifiés):

find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +

1

Des accolades dans le modèle \(\)sont requises pour le modèle de nom avecor

find Documents -type f \( -name "*.py" -or -name "*.html" \)

Alors que pour le modèle de nom avec andopérateur, il n'est pas requis

find Documents -type f ! -name "*.py" -and ! -name "*.html" 

0

Cela fonctionne sur le shell korn AIX.

find *.cbl *.dms -prune -type f -mtime -1

Ceci recherche *.cblou *.dmsqui ont 1 jour, dans le répertoire actuel uniquement, en sautant les sous-répertoires.


0
find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"

2
Notez que ce dernier correspondra à foo.jmg mais aucun des deux premiers ne le fera.
copper.hat

0

Qu'en est-il de

ls {*.py,*.html}

Il répertorie tous les fichiers se terminant par .py ou .html dans leurs noms de fichiers

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.