Voici une façon de procéder...
find . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"
pour moi, cette solution n'a pas fonctionné sur une commande exec avec find, je ne sais pas vraiment pourquoi, donc ma solution est
find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;
Explication : identique à sampson-chen one avec les ajouts de
-prune - ignore le chemin de traitement de ...
-o - Ensuite, s'il n'y a pas de correspondance, 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
Voici comment vous pouvez spécifier cela avec find
:
find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"
Explication :
find .
- Lancer la recherche à partir du répertoire de travail actuel (récursivement par défaut)-type f
- Spécifiez àfind
que vous ne voulez que des 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 commence par./scripts/
Test de 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
l'option ne considère que le nom de base, où -path
considère le chemin entier =)
Utiliser
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 évalue de gauche à droite. Commencez toujours par l'exclusion de 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 qu'une évaluation de condition.
\( \)
- opération de groupes (vous pouvez utiliser-path "./tmp" -prune -o -path "./scripts" -prune -o
, mais il est plus verbeux).-path "./script" -prune
- si-path
renvoie vrai et est un répertoire, renvoie vrai pour ce répertoire et ne pas descendez dedans.-path "./script" ! -prune
- il est évalué comme(-path "./script") AND (! -prune)
. Il ramène le "toujours vrai" de prune à toujours faux. Cela évite d'imprimer"./script"
comme un match.-path "./script" -prune -false
- depuis-prune
renvoie toujours true, vous pouvez le faire suivre de-false
faire la même chose que!
.-o
- Opérateur OU. Si aucun opérateur n'est spécifié entre deux expressions, la valeur par défaut est l'opérateur AND.
Par conséquent, \( -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'impression est importante ici car sans elle est étendue à :
{ [ (-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 depuis -prune
renvoie vrai, il affichera "./script" et "./tmp".
Ce n'est pas nécessaire dans les autres car nous avons basculé -prune
pour toujours retourner false.
Astuce :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 coché.