Frage So schließen Sie ein Verzeichnis in der Suche aus. Befehl


Ich versuche, einen Suchbefehl für alle JavaScript-Dateien auszuführen, aber wie schließe ich ein bestimmtes Verzeichnis aus?

Hier ist der Suchcode, den wir verwenden.

for file in $(find . -name '*.js'); do java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file; done

903
2017-11-17 22:57


Ursprung


Antworten:


Verwenden Sie den Prune - Schalter, wenn Sie zum Beispiel den misc Verzeichnis einfach hinzufügen a -path ./misc -prune -o zu deinem Suchbefehl:

find . -path ./misc -prune -o -name '*.txt' -print

Hier ist ein Beispiel mit mehreren Verzeichnissen:

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

Hier schließen wir dir1, dir2 und dir3 aus, da in find Ausdrücke Es ist eine Aktion, die auf die Kriterien einwirkt -path dir1 -o -path dir2 -o -path dir3 (wenn dir1 oder dir2 oder dir3), UNDed mit type -d. Weitere Aktion ist -o print, nur drucken.


701
2017-11-17 23:00



Ob -prune funktioniert nicht für dich, das wird:

find -name "*.js" -not -path "./directory/*"

1518
2018-04-01 01:26



Ich finde das Folgende leichter zu verstehen als andere vorgeschlagene Lösungen:

find build -not \( -path build/external -prune \) -name \*.js

Das kommt von einem tatsächlichen Anwendungsfall, bei dem ich Yui-Compressor für einige von Wintersmith erzeugte Dateien aufrufen musste, aber andere Dateien weglassen musste, die unverändert gesendet werden mussten.

Innerhalb \( und \) ist ein Ausdruck, der übereinstimmen wird genau  build/external (es wird nicht übereinstimmen, wenn Sie es getan haben find ./buildzum Beispiel - Sie müssen es ändern in ./build/external in diesem Fall) und wird, bei Erfolg, vermeide es, irgendetwas darunter zu durchqueren. Dies wird dann als einzelner Ausdruck mit der Escape-Klammer gruppiert und mit vorangestellt -not was machen wird find Überspringe alles, was mit diesem Ausdruck übereinstimmt.

Man könnte fragen, ob man hinzufügt -not Es werden nicht alle anderen Dateien ausgeblendet -prune wieder erscheinen, und die Antwort ist nein. Der Weg -prune funktioniert so, dass nach dem Erlangen die Dateien unterhalb dieses Verzeichnisses permanent ignoriert werden.

Dies ist auch einfach erweiterbar, um zusätzliche Ausschlüsse hinzuzufügen. Beispielsweise:

find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

341
2018-05-16 19:01



Hier besteht eindeutig Verwirrung darüber, wie die bevorzugte Syntax zum Überspringen eines Verzeichnisses aussehen sollte.

GNU Meinung

To ignore a directory and the files under it, use -prune

Aus der GNU find man-Seite

Argumentation

-prune stoppt find vom Abstieg in ein Verzeichnis. Einfach angeben -not -path wird noch in die fallen übersprungen Verzeichnis, aber -not -path wird immer falsch sein find testet jede Datei.

Probleme mit -prune

-prune tut, was es beabsichtigt ist, aber sind immer noch einige Dinge, auf die Sie achten müssen, wenn Sie es verwenden.

  1. find druckt das bereinigte Verzeichnis.

    • WAHR Das ist beabsichtigtes Verhalten, es geht einfach nicht hinein. Um zu vermeiden, dass das Verzeichnis vollständig gedruckt wird, verwenden Sie eine Syntax, die es logisch auslässt.
  2. -prune funktioniert nur mit -print und keine anderen Aktionen.

    • NICHT WAHR. -prune funktioniert mit jeder Aktion außer -delete. Warum funktioniert das nicht mit delete? Zum -delete Um zu arbeiten, muss das Verzeichnis in der DFS-Reihenfolge durchsucht werden, da -deletelöscht zuerst die Blätter, dann die Eltern der Blätter, etc ... Aber zur Angabe -prune Sinn machen, find muss ein Verzeichnis treffen und aufhören, es abzusteigen, was keinen Sinn macht mit -depth oder -delete auf.

Performance

Ich habe einen einfachen Test für die drei oben gestellten Antworten zu dieser Frage erstellt (ersetzt -printmit -exec bash -c 'echo $0' {} \; um ein anderes Aktionsbeispiel zu zeigen). Ergebnisse sind unten

----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me     702702    
.performance_test/other        2         
----------------------------------------------

> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 23513814

> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 10670141

> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

Fazit

Beide f10bit-Syntax und Daniel C. Sobrals Syntax dauerte durchschnittlich 10-25ms. GetFree-Syntax, die nicht verwendet -prune, nahm 865ms. Also, das ist ein ziemlich extremes Beispiel, aber wenn Sie sich um die Laufzeit kümmern und alles aus der Ferne tun, sollten Sie es verwenden -prune.

Hinweis Daniel C. Sobrals Syntax die bessere der beiden durchgeführt -prune Syntaxen; aber ich vermute stark, dass dies das Ergebnis von etwas Caching ist, da die Reihenfolge, in der die beiden rannten, zum entgegengesetzten Ergebnis führte, während die Nicht-Prune-Version immer am langsamsten war.

Testskript

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\'  {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup

153
2017-07-04 00:21



Eine Option wäre, alle Ergebnisse auszuschließen, die den Verzeichnisnamen mit grep enthalten. Beispielsweise:

find . -name '*.js' | grep -v excludeddir

44
2017-11-17 23:01



Ich bevorzuge die -not Notation ... es ist lesbarer:

find . -name '*.js' -and -not -path directory

37
2017-11-17 23:22



Verwenden Sie die Option -prune. Also, etwas wie:

find . -type d -name proc -prune -o -name '*.js'

Der '-type d -name proc -prune' sucht nur nach Verzeichnissen mit dem Namen proc, die ausgeschlossen werden sollen.
Das '-o' ist ein ODER-Operator.


17
2017-11-17 23:01



Dies ist das Format, das ich verwendet habe, um einige Pfade auszuschließen:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

Ich habe damit alle Dateien gefunden, die nicht in ". *" Pfaden liegen:

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

13
2018-01-18 17:06