Skriptfrage: Datei mit bestimmtem Inhalt finden
Servus zusammen, wie kann man denn elegant nach einer Datei suchen, die irgendwo in irgendeiner Reihenfolge bestimmte Stichworte enthält? Sowas finde ich grausig: grep -ril wort1 . | while read x; do grep -ril wort2 "$x"; done | while... Gibts nicht was schöneres, wo jede Datei nur einmal gelesen werden muß? -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Moin, On Tue, 14 Sep 2010, 11:05:03 +0200, Andre Tann wrote:
Servus zusammen,
wie kann man denn elegant nach einer Datei suchen, die irgendwo in irgendeiner Reihenfolge bestimmte Stichworte enthält?
Sowas finde ich grausig:
grep -ril wort1 . | while read x; do grep -ril wort2 "$x"; done | while...
Gibts nicht was schöneres, wo jede Datei nur einmal gelesen werden muß?
grep -ril -f datei-die-deine-suchmuster-enthaelt_siehe-auch-man-grep . HTH, cheers. l8er manfred -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Manfred Hollstein, Dienstag 14 September 2010:
Gibts nicht was schöneres, wo jede Datei nur einmal gelesen werden muß?
grep -ril -f datei-die-deine-suchmuster-enthaelt_siehe-auch-man-grep .
Öh, vielleicht kapier ich das nicht richtig, aber im Test findet grep dann alle Dateien, auch nur eines der Suchmuster enthalten. Die Muster werden sozusagen ODER-verknüpft, nicht UND. Oder überseh ich was? -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am Dienstag, 14. September 2010 13:09 schrieb Andre Tann:
Manfred Hollstein, Dienstag 14 September 2010:
Gibts nicht was schöneres, wo jede Datei nur einmal gelesen werden muß?
grep -ril -f datei-die-deine-suchmuster-enthaelt_siehe-auch-man-grep .
Öh, vielleicht kapier ich das nicht richtig, aber im Test findet grep dann alle Dateien, auch nur eines der Suchmuster enthalten. Die Muster werden sozusagen ODER-verknüpft, nicht UND.
Nimm 'ne Pipe: grep muster1 dateien... |grep muster2|grep muster3|grep -v ohne-dies-muster findet nur Zeilen in Dateien, in denen Muster 1 bis 3 aber nicht das letzte Muster steht... -- Herzliche Grüße! Rolf Muth Meine Adressen duerfen nicht fuer Werbung verwendet werden! PGP Public Key fuer "Rolf Muth (inet)" auf http://pgp.mit.edu/ Analoge Uhr (clock): http://www.heise.de/software/download/analoge_uhr/61872 -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Rolf Muth, Dienstag 14 September 2010:
Nimm 'ne Pipe: grep muster1 dateien... |grep muster2|grep muster3|grep -v ohne-dies-muster
findet nur Zeilen in Dateien, in denen Muster 1 bis 3 aber nicht das letzte Muster steht...
Das funktioniert leider auch nicht, denn die Muster kommen nicht in einer Zeile vor, sondern irgendwo im Dokument. Dein Vorschlag oben funktioniert nur, wenn die Muster und das "ohne-dies-muster" in einer Zeile stehen. -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
So, dann schicke ich auch noch ne Zeile ins Rennen: grep >>Line2<< `grep -ir >>Line1<< * | cut -f 1 -d ":" ` Also, grep nach Line2 in jedem File in dem du vorher Line1 gefunden hast. Grüsse Am 14.09.2010 14:40, schrieb Andre Tann:
Rolf Muth, Dienstag 14 September 2010:
Nimm 'ne Pipe: grep muster1 dateien... |grep muster2|grep muster3|grep -v ohne-dies-muster
findet nur Zeilen in Dateien, in denen Muster 1 bis 3 aber nicht das letzte Muster steht...
Das funktioniert leider auch nicht, denn die Muster kommen nicht in einer Zeile vor, sondern irgendwo im Dokument.
Dein Vorschlag oben funktioniert nur, wenn die Muster und das "ohne-dies-muster" in einer Zeile stehen.
-- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Jörg Stephan, Dienstag 14 September 2010:
grep >>Line2<< `grep -ir >>Line1<< * | cut -f 1 -d ":" `
Also, grep nach Line2 in jedem File in dem du vorher Line1 gefunden hast.
...wenn Du dann nach zehn Mustern suchen willst, dann greppst Du jede Datei bis zu zehnmal. Das funktioniert, keine Frage, aber schön oder effektiv ist das nicht. -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Andre Tann schrieb:
Rolf Muth, Dienstag 14 September 2010:
Nimm 'ne Pipe: grep muster1 dateien... |grep muster2|grep muster3|grep -v ohne-dies-muster
wenn dann doch bitte mit egrep "Muster1|Muster2|Muster3" *.dateipattern -- Gruß Axel ------------------------------ => einen Server härten? google mal nach Stahl härten oder was meinst Du mit härten? Aus: http://www.administrator.de/index.php?content=69906 ------------------------------ http://www.tty1.net/smart-questions_de.html -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am Dienstag, 14. September 2010 14:40 schrieb Andre Tann:
Rolf Muth, Dienstag 14 September 2010:
Nimm 'ne Pipe: grep muster1 dateien... |grep muster2|grep muster3|grep -v ohne-dies-muster
findet nur Zeilen in Dateien, in denen Muster 1 bis 3 aber nicht das letzte Muster steht...
Das funktioniert leider auch nicht, denn die Muster kommen nicht in einer Zeile vor, sondern irgendwo im Dokument.
Dein Vorschlag oben funktioniert nur, wenn die Muster und das "ohne-dies-muster" in einer Zeile stehen. Du hast natürlich vollkommen recht! (vor den Schädel schlag...)
-- Herzliche Grüße! Rolf Muth Meine Adressen duerfen nicht fuer Werbung verwendet werden! PGP Public Key fuer "Rolf Muth (inet)" auf http://pgp.mit.edu/ Analoge Uhr (clock): http://www.heise.de/software/download/analoge_uhr/61872 -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am 14.09.2010 11:05, schrieb Andre Tann:
Servus zusammen,
wie kann man denn elegant nach einer Datei suchen, die irgendwo in irgendeiner Reihenfolge bestimmte Stichworte enthält?
Sowas finde ich grausig:
grep -ril wort1 . | while read x; do grep -ril wort2 "$x"; done | while...
Gibts nicht was schöneres, wo jede Datei nur einmal gelesen werden muß?
im aktuellen Verzeichnis in JSP Datein suchen: find . -name "*.jsp" -exec grep -nH "zufindendenText" {} \; statt *.jsp geht auch "*" für alle Datein -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
On Tuesday, September 14, 2010 11:05:03 Andre Tann wrote:
Sowas finde ich grausig:
grep -ril wort1 . | while read x; do grep -ril wort2 "$x"; done | while...
Gibts nicht was schöneres, wo jede Datei nur einmal gelesen werden muß?
Du willst alle Dateien finden, die sowohl wort1 als auch wort2 enthalten, richtig? Sind die Dateien nicht zu groß könnte folgendes Perl-Kommando helfen. Ich habe versucht, nur wenig Perl zu verwenden. Man kann natürlich auch das rekursive Wandern durch den Verzeichnisbaum recht einfach in Perl durchführen. Auch liest das Script jede Datei komplett in den RAM. Für richtig große Dateien ist das also ungeeignet. "bin" und "root" ist wohl in jeder /etc/passwd und /etc/group enthalten, aber in /etc/motd eher seltener. Im Perl-Code selbst kannst Du alle Leerzeichen weglassen, wenn Du willst. find /etc/passwd /etc/group /etc/motd -type f -print0 | xargs -0 perl -le ' undef $/; for $n (@ARGV) { local @ARGV=($n); local $_=<>; /bin/ && /root/ && print $n; }' Torsten Förtsch -- Need professional modperl support? Hire me! (http://foertsch.name) Like fantasy? http://kabatinte.net -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Die, 14 Sep 2010, Andre Tann schrieb:
wie kann man denn elegant nach einer Datei suchen, die irgendwo in irgendeiner Reihenfolge bestimmte Stichworte enthält?
Sowas finde ich grausig:
grep -ril wort1 . | while read x; do grep -ril wort2 "$x"; done | while...
Gibts nicht was schöneres, wo jede Datei nur einmal gelesen werden muß?
==== find . -type f -exec gawk ' BEGIN { N = NUM_WORDS; } /wort1/ && ! words[1] { words[1]=1; } /wort2/ && ! words[2] { words[2]=1; } ... /wortN/ && ! words[N] { words[N]=1; } END { for(i in words) { n++; } if ( n == N ) { print FILENAME; } }' '{}' + ==== Alternativ: ==== find . -type f -exec gawk ' /wort1/ { words[1]=1; } /wort2/ { words[2]=1; } ... /wortN/ { words[N]=1; } END { if( words[1] && words[2] && ... && words[N] ) { print FILENAME; } }' '{}' + ==== Wobei beidemale "wort1" ... "wortN" für Regexe stehen (wie bei egrep). Und NUM_WORDS beim ersten in die Anzahl der Regexe. Den Krams mit den '/wortN/ { words[N] = 1; }' könnte man auch generieren, und das ganze dann an gawk -f verfüttern: ==== { echo 'BEGIN { print FILENAME; }' i=1 for regex in foo 'bar.*baz' qux; do printf '/%s/ { words[%s]=1; }\n' "$regex" "$i" i=$((i+1)) done echo -n 'END { if (' j=1 while test $j -lt $i ; do echo "words[$j] &&"; j=$((j+1)); done printf '1 ) {\n print FILENAME;\n}}' } > /tmp/t.awk find . -type f -exec gawk -f /tmp/t.awk '{}' + rm -f /tmp/t.awk ==== Zum Nachverfolgen noch ein 'cat /tmp/t.awk' vor dem 'find' einbauen. Und das find ggfs. auskommentieren. Das kann man dann noch so ausbauen, daß man 'for regex in "$@"; do' verwendet und in ein Script verpackt (dann sollte man allerdings 'mktemp' für ein sicheres tempfile verwenden!). Könnte man dann z.B. als ~/bin/multigrep abspeichern. Zur Erinnerung: sed kann alles was grep kann, awk kann alles was sed kann, perl kann (fast) alles was awk kann ;) (und jew. noch einiges mehr). HTH, noch Fragen? -dnh -- There is a green, multi-legged creature crawling on your shoulder. -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
David Haller, Dienstag 14 September 2010:
find . -type f -exec gawk ' BEGIN { N = NUM_WORDS; } /wort1/ && ! words[1] { words[1]=1; } /wort2/ && ! words[2] { words[2]=1; } ^^^^^^^^^^^^^ Verstehe ich das richtig: Du prüfst damit, ob words[2] schon gesetzt ist. Wozu? Woher sollte es gesetzt sein?
... /wortN/ && ! words[N] { words[N]=1; } END { for(i in words) { n++; } if ( n == N ) { print FILENAME; } }' '{}' +
^ Das beschleunigt einfach die Sache, weil awk mit seinem Skript mehrere Files auf einmal präsentiert bekommt, richtig? Warum muß das '{}' in Hochkomma? Ich hab mal vor einiger Zeit explizit danach gefragt, und da meinte irgend jemand, daß Quoting hier nicht nötig sei, weil find das {} nicht einfach durch den gefundenen Dateinamen ersetzt, als wäre er hingeschrieben worden, sondern er wird sozusagen schon gequotet behandelt.
HTH, noch Fragen?
Ja, vermutlich schon, muß mich aber erst noch weiter einwühlen, dauert noch. Danke erstmal... -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Andre Tann, Mittwoch 15 September 2010:
David Haller, Dienstag 14 September 2010:
find . -type f -exec gawk ' BEGIN { N = NUM_WORDS; } /wort1/ && ! words[1] { words[1]=1; } /wort2/ && ! words[2] { words[2]=1; }
^^^^^^^^^^^^^ Verstehe ich das richtig: Du prüfst damit, ob words[2] schon gesetzt ist. Wozu? Woher sollte es gesetzt sein?
OK, Denkfehler. Die Schleife wird ja für jede Zeile durchlaufen, also öfter, also könnte es vom vorherigen Durchlauf gesetzt sein. Trotzdem die Frage: Was würde es schaden, wenn ich words[1]=1 setze, auch wenn das zuvor schon gemacht wurde? Davon abgesehen jage ich das Skript gerade durch mein Mailverzeichnis, und es wirft viel zu wenige Treffer aus. Ich habe nach /atann/ und /alphasrv/ gesucht, und da gibts genau sieben Treffer in ca. 20.000 Maildateien. Das ist etwas zuwenig... ;) Irgendwas stimmt da noch nicht. -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Mit, 15 Sep 2010, Andre Tann schrieb:
Andre Tann, Mittwoch 15 September 2010:
David Haller, Dienstag 14 September 2010:
find . -type f -exec gawk ' BEGIN { N = NUM_WORDS; } /wort1/ && ! words[1] { words[1]=1; } /wort2/ && ! words[2] { words[2]=1; }
^^^^^^^^^^^^^ Verstehe ich das richtig: Du prüfst damit, ob words[2] schon gesetzt ist. Wozu? Woher sollte es gesetzt sein?
OK, Denkfehler.
Meinerseits.
Die Schleife wird ja für jede Zeile durchlaufen, also öfter, also könnte es vom vorherigen Durchlauf gesetzt sein.
Hm, da hast du wohl recht. So klappts: find . -type f -exec gawk ' function endfile() { if( words[1] && words[2] && words[3] ) { print lastfile; } } lastfile != FILENAME { endfile(); words[1] = 0; words[2] = 0; words[3] = 0; lastfile = FILENAME; } /wort1/ { words[1]=1; } /wort2/ { words[2]=1; } /wort3/ { words[3]=1; } END { endfile(); } ' '{}' +
Trotzdem die Frage: Was würde es schaden, wenn ich words[1]=1 setze, auch wenn das zuvor schon gemacht wurde?
s.o. Wenn du willst kannst du zusätzlich noch die Treffer zählen, Muster: /wort1/ { words[1]++; } und: function endfile() { if( words[1] && words[2] && words[3] ) { print lastfile; print "wort1: " words[1]; print "wort2: " words[2]; } } Oder so ähnlich. Wobei man das auch noch besser schreiben könnte (statt numerisch durch die Regexe als string indizieren.
Davon abgesehen jage ich das Skript gerade durch mein Mailverzeichnis, und es wirft viel zu wenige Treffer aus. Ich habe nach /atann/ und /alphasrv/ gesucht, und da gibts genau sieben Treffer in ca. 20.000 Maildateien. Das ist etwas zuwenig... ;) Irgendwas stimmt da noch nicht.
Liegt an meinem Denkfehler, s.o. HTH, -dnh -- Power corrupts, PowerPoint corrupts absolutely. -- Vint Cerf -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Servus David, sorry, ich kapier gar nix, und hake nochmal nach: David Haller, Mittwoch 15 September 2010: 1 find . -type f -exec gawk ' 2 function endfile() { 3 if( words[1] && words[2] && words[3] ) { 4 print lastfile; 5 } 6 } 7 lastfile != FILENAME { 8 endfile(); 9 words[1] = 0; words[2] = 0; words[3] = 0; 10 lastfile = FILENAME; 11 } 12 /wort1/ { words[1]=1; } 13 /wort2/ { words[2]=1; } 14 /wort3/ { words[3]=1; } 15 END { endfile(); } 16 ' '{}' + In Zeile 10 wird lastfile = FILENAME gesetzt, und erst dann ist Zeile 7 erfüllt. Wie kann es dazu kommen, daß Zeile 7 erfüllt ist, ohne daß Zeile 10 vorher durchlaufen wurde? Ich sehe, daß Dein Skript funktioniert. Folgendes Skript funktioniert aber auch: find ~/Mail -type f -exec gawk ' /wort1/ { words[1]=1; } /wort2/ { words[2]=1; } /wort3/ { words[3]=1; } END { if ( words[1] && words[2] && words[3] ) { print FILENAME; } }' '{}' \; Das ist viel einfacher als Deines, auch wenn Deines etwas schneller ist: Deines braucht 3:59, um meinen Mailspool umzugraben, meines 4:35. Danke+Gruß! -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Mit, 15 Sep 2010, Andre Tann schrieb:
sorry, ich kapier gar nix, und hake nochmal nach:
David Haller, Mittwoch 15 September 2010:
1 find . -type f -exec gawk ' 2 function endfile() { 3 if( words[1] && words[2] && words[3] ) { 4 print lastfile; 5 } 6 } 7 lastfile != FILENAME { 8 endfile(); 9 words[1] = 0; words[2] = 0; words[3] = 0; 10 lastfile = FILENAME; 11 } 12 /wort1/ { words[1]=1; } 13 /wort2/ { words[2]=1; } 14 /wort3/ { words[3]=1; } 15 END { endfile(); } 16 ' '{}' +
In Zeile 10 wird lastfile = FILENAME gesetzt, und erst dann ist Zeile 7 erfüllt. Wie kann es dazu kommen, daß Zeile 7 erfüllt ist, ohne daß Zeile 10 vorher durchlaufen wurde?
Das dient dazu, zu erkennen, ab wann eine neue Datei bearbeitet wird, und genau das war mein Denkfehler, der in der Version unten drin ist (siehe dort). Also, du hast z.B. im mailspool die Dateien 1-60, davon übergibt find sagen wir zuerst 40 und dann 20 an gawk. Bei Datei 1 ist lastfile leer und FILENAME == "1". Zeile 7 greift, aber words[] ist noch leer. endfile wird nicht aufgerufen und words[] zurückgesetzt. lastfile wird auf FILENAME ("1") gesetzt. Zeilen 12 - 14 greifen evtl. und words[] wird befüllt (oder auch nicht). Und bei allen Zeilen der Datei ist nun lastfile == FILENAME, Zeile 7 greift nicht. END {} greift _NICHT_. Also weiter mit der nächsten Datei. lastfile == "1", FILENAME == "2", words[] ist mit den Treffern aus Datei 1 "gefüllt". Durch Zeile 7 wird erkannt, daß nicht mehr Datei 1 gelesen wird. Also: endfile aufrufen und gucken, ob's Treffer in Datei 1 gab , ggfs. den Dateinamen (lastfile == "1") dazu ausgeben. Dann noch lastfile auf den neuen Dateinamen FILENAME == "2" setzen und Datei 2 durchgehen (analog zu Datei 1). Am Ende von Datei 40 greift dann Zeile 7 nicht mehr (FILENAME ist immer noch == lastfile == "40"). Dafür greift aber die END Bedingung, also auch hier noch nach Treffern gucken und ggfs. lastfile == FILENAME == "40" ausgeben. Und fertig. Beim zweiten Schwung Dateien das gleiche, aber eben mit Dateien 41 - 60. Ich hoffe du kannst das nachvollziehen ;) Oh, und du kannst die Bedingung, was vorkommen muß oder darf auch noch ausgestalten, z.B.: function endfile() { if( words[1] && ( words[2] || words[3] ) && words[4] ) { print lastfile; } } Also 1 UND ( 2 ODER 3 ) UND 4 in bel. Reihenfolge(!). Deswegen müßte man auch bei perl mit einem Hash arbeiten (genau wie hier im awk) oder mit einer komplexen RE (die alle Permutationen der Reihenfolge enthalten muß) die ganze Datei angucken (das ist lahm und braucht Speicher. Für obige nur 3 Bedingungen wären das (in perl): m/ 1.*(2|3).*4 | 1.*4.*(2|3) | (2|3).*1.*4 | (2|3).*4.*1 | 4.*(2|3).*1 | 4.*1.*(2|3) /xgs; Bei 5 Bed. wären es schon 5! = 120 Regexe die man hinschreiben (oder generieren müßte). Und bei 10 Bed. is wohl Feierabend: 10! = 3,628,800 Viel Spaß (und grottige Performance, wenn du auch nur 120 REs mit ner ganzen Datei vergleichst)! Mit nem Hash und zeilenweiser Suche in awk (hier eben "array") oder perl ist sowas aber kein Problem, wie ich ja demonstriere. Und wenn was auf einer Zeile vorkommen muß, mußt du eben die passende RE dazu angeben, z.B. für 'wort1': /^From: .*atann@/ { words[1] = 1; } Du kannst das Array "words" auch mit Strings indizieren (wenn du es explizit auswertest, sonst brauchst du noch ein Array der Indices, das wird ein bissl kompliziert jetzt, aber wenn du eben "explizit" darauf zugreifst geht genauso: 2 function endfile() { 3 if( words["From"] && words["Subject"] ) { 4 print lastfile; 5 } 6 } 7 lastfile != FILENAME { 8 endfile(); 9 words["From"] = 0; words["Subject] = 0; 10 lastfile = FILENAME; 11 } 12 /^From: .*atann@/ { words["From"]=1; } 13 /^Subject: .*(foo|bar)/ { words["Subject"]=1; } (wobei man evtl. die Variable words in "found" umbenennen sollte ;) Bei Mails mußt du auch noch beachten, daß die Header (auch From und natürlich Subject) kodiert sein müssen (Quoted-Printable oder Base64). In dem Fall ist es dann einfacher doch perl zu verwenden, damit kannst du die Header bequem parsen und dekodieren und dann durchsuchen, was ich z.B. mit den c't-Register-Updates mache [1].
Ich sehe, daß Dein Skript funktioniert. Folgendes Skript funktioniert aber auch:
find ~/Mail -type f -exec gawk ' /wort1/ { words[1]=1; } /wort2/ { words[2]=1; } /wort3/ { words[3]=1; } END { if ( words[1] && words[2] && words[3] ) { print FILENAME; } }' '{}' \;
Das ist viel einfacher als Deines, auch wenn Deines etwas schneller ist: Deines braucht 3:59, um meinen Mailspool umzugraben, meines 4:35.
Der Denkfehler hier ist: END greift nur bei der letzten Datei eines Schwungs, und words[] enthält Treffer aus allen Dateien (1-40, 41-60), ausgegeben wird aber jew. der letzte Dateiname (40, 60) wenn in allen Dateien eines Schwungs die Such-Regexe "trafen" egal wie diese Treffer über die Dateien verteilt waren. Meinetwegen z.B. "wort1" in Datei 1, wort2 in Datei 2 ... Ausgegeben wird aber "40", selbst wenn in der gar nix passte. Solltest du evtl. sogar anhand von ein paar (ausgewählten) Dateien testen können ;) Achso: awk kann auch einen Stringvergleich (-> vgl. 'fgrep'): $0 == "wort1" { ...; } (dann muß aber "wort1" die gesamte Zeile sein, ggfs. kann man das aber ausnützen, z.B. bei Mails direkt das From: angucken): gawk -F':' ' ### : als Feldtrenner -> Mailheader wird am : geteilt in ### $1 und $2 (beide ohne den ":"). $1 == "From" { ### $1 = Headername if( $2 ~ /atann@/ ) { ### $2 = Headerinhalt, hier nun Suche ### per Regex mail_ist_von_mir = 1; } } /^$/ { nextfile; ### nur den Header angucken: erste Leerzeile -> ### weiter zur nächsten Datei } ### ... ' Achso, so längliche und kommentierte Scripte würde ich als Dateien speichern und ausführbar machen: ==== ~/bin/mailsuche ==== #!/usr/bin/gawk -f ... ==== und dann eben find ... -exec mailsuche '{}' + wobei man ggfs. auch noch Regexe/Suchwörter per Variable beim Aufruf übergeben könnte, wenn man das Script flexibler machen will. Kurzum: awk ist für viele Dinge ein sehr praktisches Programm bzw. genauer eine sehr praktische Scriptsprache. So, alle Klarheiten beseitigt? Geschafft vom kl. Awk-Kurs? :) Und die Behauptung anderswo im Thread, man könne nicht in mehreren Dateien nach mehreren Regexen suchen ohne die Dateien mehrfach zu lesen, habe ich wohl auch widerlegt. :P HTH, -dnh PS: mach doch noch mal nen Benchmark ggü. der grep | grep | grep Variante ;) [1] passende Mail wird in procmail identifiziert und an mein perlscript verfüttert. Das sucht dann den passenden Anhang mit dem eigentlichen Update, pfriemelt den raus und ruft dann gleich noch ctreg.pl auf um den das Update einzuspielen und Register Index zu aktualisieren ;) Wg. Details am Script bei Interesse bitte PM. --
... Bücher sind ein grässliches Medium ... Ich schätze daran die leichte Portierbarkeit vom Sofa ins Bett. [Bjoern Hoehrmann und Peter Bieling in dciwam] -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Servus David, David Haller, Mittwoch 15 September 2010:
So, alle Klarheiten beseitigt? Geschafft vom kl. Awk-Kurs? :)
Keineswegs. Kam nur bisher nicht dazu, mich nochmal damit auseinanderzusetzen. Hab ich aber jetzt, und ich glaub, jetzt hab ich awk erstmal soweit kapiert. Danke für die ausführlichen Beschreibungen.
PS: mach doch noch mal nen Benchmark ggü. der grep | grep | grep Variante ;)
Naja, das ist nicht ganz fair. Aber mache ich noch, und schreib das Ergebnis. Eine Frage aber noch: In der vorigen Mail schrieb ich:
Ich sehe, daß Dein Skript funktioniert. Folgendes Skript funktioniert aber auch:
find ~/Mail -type f -exec gawk ' wort1 { words[1]=1; } wort2 { words[2]=1; } wort3 { words[3]=1; } END { if ( words[1] && words[2] && words[3] ) { print FILENAME; } }' '{}' \;
Das ist viel einfacher als Deines, auch wenn Deines etwas schneller ist: Deines braucht 3:59, um meinen Mailspool umzugraben, meines 4:35.
Gibts denn an diesem Skript außer der Performance etwas auszusetzen? Denn übersichtlicher ist es doch auf jeden Fall. Danke+Gruß! -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Sam, 25 Sep 2010, Andre Tann schrieb:
David Haller, Mittwoch 15 September 2010:
PS: mach doch noch mal nen Benchmark ggü. der grep | grep | grep Variante ;)
Naja, das ist nicht ganz fair. Aber mache ich noch, und schreib das Ergebnis.
:)
Eine Frage aber noch: In der vorigen Mail schrieb ich:
Ich sehe, daß Dein Skript funktioniert. Folgendes Skript funktioniert aber auch:
find ~/Mail -type f -exec gawk ' wort1 { words[1]=1; } wort2 { words[2]=1; } wort3 { words[3]=1; } END { if ( words[1] && words[2] && words[3] ) { print FILENAME; } }' '{}' \;
Das ist viel einfacher als Deines, auch wenn Deines etwas schneller ist: Deines braucht 3:59, um meinen Mailspool umzugraben, meines 4:35.
Gibts denn an diesem Skript außer der Performance etwas auszusetzen? Denn übersichtlicher ist es doch auf jeden Fall.
Siehe _oben_ in meiner letzten Mail bzgl. meines Denkfehlers. -dnh -- Ich hab von der Betriebsärztin eine Fußstütze verordnet bekommen. Ist ja durchaus bequem. Nun suche ich nach einer Möglichkeit, das Ding als Fußpedal für einen zusätzlichen Modifier im Emacs einzubinden. -- Stefan Reuther -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
On 09/14/2010 11:05 AM, Andre Tann wrote:
Servus zusammen,
wie kann man denn elegant nach einer Datei suchen, die irgendwo in irgendeiner Reihenfolge bestimmte Stichworte enthält?
Sowas finde ich grausig:
grep -ril wort1 . | while read x; do grep -ril wort2 "$x"; done | while...
Gibts nicht was schöneres, wo jede Datei nur einmal gelesen werden muß?
suche=(wort1 wort2 wort3 wortn) find . -type f -exec egrep "`echo ${suche[*]}|sed 's/\ /\|/g'`" /dev/null {} \; Das sollte deiner Vorstellung entsprechen Viele Grüße Egon -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Die, 14 Sep 2010, Egon Schmid schrieb:
On 09/14/2010 11:05 AM, Andre Tann wrote:
wie kann man denn elegant nach einer Datei suchen, die irgendwo in irgendeiner Reihenfolge bestimmte Stichworte enthält? [..] suche=(wort1 wort2 wort3 wortn) find . -type f -exec egrep "`echo ${suche[*]}|sed 's/\ /\|/g'`" /dev/null {} \;
Das sollte deiner Vorstellung entsprechen
Das glaub ich ganz und gar nicht. ${VAR[*]} ist schon generell ungeignet, und wenn du schon nach dem simpelsten Fall 'foo bar' suchen willst, fällst du mit deiner Lösung auf die Schnauze ... Und das ganz abgesehen davon, daß wohl eine "UND" Suche nach den "Worten" irgendwo in der Datei gesucht ist, und du eine zeilenweise "ODER" Suche draus machst. Und daß das find in dem Fall überflüssig ist. Hast du den Thread bisher nicht gelesen? -dnh -- Who says we only flame newbies? We flame anything that moves and isn't properly charred yet. -- Peter Seebach -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hi Egon! On Di, 14 Sep 2010, Egon Schmid wrote:
suche=(wort1 wort2 wort3 wortn) find . -type f -exec egrep "`echo ${suche[*]}|sed 's/\ /\|/g'`" /dev/null {} \;
Warum nicht gleich mit sed suchen? Mit freundlichen Grüßen, Christian -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo Leute Am Dienstag, 14. September 2010, 20:26:17 schrieb Christian Brabandt:
suche=(wort1 wort2 wort3 wortn) find . -type f -exec egrep "`echo ${suche[*]}|sed 's/\ /\|/g'`" /dev/null {} \;
Warum nicht gleich mit sed suchen?
Bei der Gelgenheit schicke ich auch noch einen Vorschlag ins Rennen. Man kann nur dazuzlernen: (alles auf einer Zeile): find -type f | while read a ; do b=`cat $a` ; c=`echo $b | grep wort1 | grep wort2 | grep -c wort3` ; if [ $c -gt 0 ] ; then echo $a ; fi ; done - Variable a ist klar. - Variable b benutze ich hier, weil ein echo von $b den ganzen Inhalt in einer Zeile ausgiebt. - bei Variable c interessiert mich nur die Zahl die beim letzten grep durch die Option -c rauskommt. Ist diese größer als 0 kann ich davon ausgehen, das alle Worte vorhanden waren. Hätte ein Wort gefehlt, dann wäre am Ende der grep's 0 rausgekommen. Ich hoffe ich habe nicht zu umständlich gedacht. Viele Grüße Peter -- ######################################################################## ######################################################################## ######################################################################## ######################################################################## -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Egon Schmid, Dienstag 14 September 2010:
suche=(wort1 wort2 wort3 wortn) find . -type f -exec egrep "`echo ${suche[*]}|sed 's/\ /\|/g'`" /dev/null {} \;
Vielleicht kapier ich das nicht richtig, aber was ist denn der Unterschied zwischen obiger Zeile und dieser hier: egrep -rl "wort1|wort2|wort3" . ? -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo Andre Am Mittwoch, 15. September 2010, 07:42:53 schrieb Andre Tann:
suche=(wort1 wort2 wort3 wortn) find . -type f -exec egrep "`echo ${suche[*]}|sed 's/\ /\|/g'`" /dev/null
{} \;
Vielleicht kapier ich das nicht richtig, aber was ist denn der Unterschied zwischen obiger Zeile und dieser hier:
egrep -rl "wort1|wort2|wort3" .
Im Endeffekt ist es genau das selbe. Nur mit dem Unterschied, das in obigen Beispiel die Worte erst in ein Array geschrieben werden und dann beim Auslesen die Leerzeeichen durch | ersetzt werden müssen. Viele Grüße Peter -- ######################################################################## ######################################################################## ######################################################################## ######################################################################## -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hi Peter! On Mi, 15 Sep 2010, Peter Steffinger wrote:
Im Endeffekt ist es genau das selbe. Nur mit dem Unterschied, das in obigen Beispiel die Worte erst in ein Array geschrieben werden und dann beim Auslesen die Leerzeeichen durch | ersetzt werden müssen.
und mindestens 2 Prozesse extra gestartet werden müssen. Und portabel ist es auch nicht. Mit freundlichen Grüßen Christian -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo! Noch ein Versuch: for file in *; do $(echo -e "WORT1\nWORT2\nWORT3" | while read x ; do grep -q "$x" "$file"; if test $? -ne 0; then exit 1; fi; done); if test $? -eq 0; then printf "%s\n" "$file"; fi; done Gruß, Kimmo -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am 14.09.2010 11:05, schrieb Andre Tann:
wie kann man denn elegant nach einer Datei suchen, die irgendwo in irgendeiner Reihenfolge bestimmte Stichworte enthält?
Sowas finde ich grausig:
grep -ril wort1 . | while read x; do grep -ril wort2 "$x"; done | while...
Gibts nicht was schöneres, wo jede Datei nur einmal gelesen werden muß?
So, dann finally: Nö, gibt es nicht :-) grüsse Jörg -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
participants (12)
-
Andre Tann
-
Axel Birndt
-
Christian Brabandt
-
David Haller
-
Egon Schmid
-
Johannes Wolfgang Woger
-
Jörg Stephan
-
K. Elo
-
Manfred Hollstein
-
Peter Steffinger
-
Rolf Muth
-
Torsten Förtsch