104 votes

Utiliser la commande find mais exclure les fichiers de deux répertoires

Je veux trouver les fichiers qui se terminent par _peaks.bed mais exclure les fichiers du répertoire tmp y scripts les dossiers.

Ma commande est la suivante :

 find . -type f \( -name "*_peaks.bed" ! -name "*tmp*" ! -name "*scripts*" \)

Mais ça n'a pas marché. Les fichiers dans tmp y script sera toujours affiché.

Quelqu'un a-t-il des idées à ce sujet ?

214voto

sampson-chen Points 13413

Voici comment vous pouvez le spécifier avec find :

find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"

Explication :

  • find . - Démarrer la recherche à partir du répertoire de travail actuel (de manière récursive par défaut)
  • -type f - Spécifier à find que vous voulez seulement les fichiers dans les résultats
  • -name "*_peaks.bed" - Recherchez les fichiers dont le nom se termine par _peaks.bed
  • ! -path "./tmp/*" - Exclure tous les résultats dont le chemin commence par ./tmp/
  • ! -path "./scripts/*" - Exclure également tous les résultats dont le chemin d'accès commence par ./scripts/

Tester la solution :

$ mkdir a b c d e
$ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
$ find . -type f ! -path "./a/*" ! -path "./b/*"

./d/4
./c/3
./e/a
./e/b
./e/5

Vous étiez assez proche, le -name ne prend en compte que le nom de base, alors que l'option -path considère tout le chemin =)

8voto

alex Points 186293

Voici une façon de le faire...

find . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"

7voto

f380cedric Points 30

Utilisez

find \( -path "./tmp" -o -path "./scripts" \) -prune -o  -name "*_peaks.bed" -print

ou

find \( -path "./tmp" -o -path "./scripts" \) -prune -false -o  -name "*_peaks.bed"

ou

find \( -path "./tmp" -path "./scripts" \) ! -prune -o  -name "*_peaks.bed"

L'ordre est important. Il s'évalue de gauche à droite. Commencez toujours par l'exclusion du chemin.

Explication

Ne pas utiliser -not (ou ! ) pour exclure tout le répertoire. Utilisez -prune . Comme expliqué dans le manuel :

−prune    The primary shall always evaluate as  true;  it
          shall  cause  find  not  to descend the current
          pathname if it is a directory.  If  the  −depth
          primary  is specified, the −prune primary shall
          have no effect.

et dans le manuel GNU find :

-path pattern
              [...]
              To ignore  a  whole
              directory  tree,  use  -prune rather than checking
              every file in the tree.

En effet, si vous utilisez -not -path "./pathname" , find évaluera l'expression pour chaque nœud sous "./pathname" .

Les expressions de recherche ne sont que des évaluations de conditions.

  • \( \) - opération de groupe (vous pouvez utiliser -path "./tmp" -prune -o -path "./scripts" -prune -o mais il est plus verbeux).
  • -path "./script" -prune - si -path retourne true et est un répertoire, retourne true pour ce répertoire et fait no y descendre.
  • -path "./script" ! -prune - il est évalué comme (-path "./script") AND (! -prune) . Il renverse le "toujours vrai" de prune en toujours faux. Il évite d'imprimer "./script" comme une correspondance.
  • -path "./script" -prune -false - depuis -prune retourne toujours vrai, vous pouvez le suivre avec -false pour faire la même chose que ! .
  • -o - Opérateur OR. Si aucun opérateur n'est spécifié entre deux expressions, l'opérateur AND est utilisé par défaut.

D'où, \( -path "./tmp" -o -path "./scripts" \) -prune -o -name "*_peaks.bed" -print est étendu à :

[ (-path "./tmp" OR -path "./script") AND -prune ] OR ( -name "*_peaks.bed" AND print )

L'empreinte est importante ici, car sans elle, il y a expansion :

{ [ (-path "./tmp" OR -path "./script" )  AND -prune ]  OR (-name "*_peaks.bed" ) } AND print

-print est ajouté par find - c'est pourquoi la plupart du temps, vous n'avez pas besoin de l'ajouter dans votre expression. Et puisque -prune retourne vrai, il imprimera "./script" et "./tmp".

Ce n'est pas nécessaire dans les autres parce que nous avons échangé -prune pour qu'il renvoie toujours false.

Conseil : Vous pouvez utiliser find -D opt expr 2>&1 1>/dev/null pour voir comment il est optimisé et étendu,
find -D search expr 2>&1 1>/dev/null pour voir quel chemin est vérifié.

1voto

Al3x Points 163

Pour moi, cette solution n'a pas fonctionné sur une commande exec avec find, je ne sais pas vraiment pourquoi, donc ma solution est la suivante

find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

Explication : même que sampson-chen one avec les ajouts de

-prune - ignore le chemin de procédure de ...

-o - Ensuite, si aucune correspondance n'est trouvée, imprimez les résultats (élaguez les répertoires et imprimez les résultats restants).

18:12 $ mkdir a b c d e
18:13 $ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
18:13 $ find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

gzip: . is a directory -- ignored
gzip: ./a is a directory -- ignored
gzip: ./b is a directory -- ignored
gzip: ./c is a directory -- ignored
./c/3:    0.0% -- replaced with ./c/3.gz
gzip: ./d is a directory -- ignored
./d/4:    0.0% -- replaced with ./d/4.gz
gzip: ./e is a directory -- ignored
./e/5:    0.0% -- replaced with ./e/5.gz
./e/a:    0.0% -- replaced with ./e/a.gz
./e/b:    0.0% -- replaced with ./e/b.gz

1voto

Jacky Jiang Points 11

Vous pouvez essayer ci-dessous :

find ./ ! \( -path ./tmp -prune \) ! \( -path ./scripts -prune \) -type f -name '*_peaks.bed'

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X