Discussion:
Suche grep, das whitespace ignoriert
(zu alt für eine Antwort)
Martin Klaiber
2008-01-13 13:56:30 UTC
Permalink
Ich suche ein grep (oder ähnliches tool), das whitespace ignorieren
kann. Zweck ist die Suche nach Telefonnummern, die Leerzeichen
enthalten können.

Beispiel: die Telefonnummer 1234567 wird oft in einer der folgenden
Formen abgespeichert:

1 23 45 67
123 45 67
12 34 567

Alle sollen gefunden werden. Eine Möglichkeit wäre natürlich, im Text
einfach Leerzeichen innerhalb von Telefonnummer zu verbieten, aber das
schränkt die Lesbarkeit für Menschen ein, scheidet also aus. Auch die
Lösung, eine feste Schreibweise vorzuschreiben, scheitert in der Regel
am Faktor Mensch.

Schön wäre ein grep, das Leerzeichen ignorieren könnte. Ich habe aber
nichts in der Richtung gefunden. Zur Zeit behelfe ich mir damit:

cat telefon.dat | sort | while read zeile; do
echo "$zeile" | sed 's/\ //g' | grep -iq $1 && \
{
echo "$zeile" | ...
...
}
done

Das funktioniert zwar, ist aber ziemlich langsam. Weiß jemand, woran
das liegt, und wie man das verbessern könnte?

TIA, Martin
Alexander Bartolich
2008-01-13 14:27:27 UTC
Permalink
Post by Martin Klaiber
[...]
cat telefon.dat | sort | while read zeile; do
echo "$zeile" | sed 's/\ //g' | grep -iq $1 && \
{
echo "$zeile" | ...
...
}
done
Das funktioniert zwar, ist aber ziemlich langsam. Weiß jemand,
woran das liegt, und wie man das verbessern könnte?
Eine Schleife in der Shell ist an sich schon langsam. In der Schleife
dann noch zwei Prozesse pro Zeile zu erzeugen ist furchtbar. Die Lösung
besteht darin, die Schleife aus der Shell rauszuziehen. Dafür eignen
sich perl, awk oder sed.

Mit GNU sed sieht das so aus:

sed -ne "h; s/[[:blank:]]//g; /$1/I { g; p }" telefon.dat

Wenn dein sed die Option "I" (für case insensitive) nicht hat,
kannst du das mit y/A-Z/a-z/ annähernd ersetzen.

--
Heike C. Zimmerer
2008-01-13 14:53:23 UTC
Permalink
Post by Martin Klaiber
Ich suche ein grep (oder ähnliches tool), das whitespace ignorieren
kann. Zweck ist die Suche nach Telefonnummern, die Leerzeichen
enthalten können.
Schön wäre ein grep, das Leerzeichen ignorieren könnte. Ich habe aber
cat telefon.dat | sort | while read zeile; do
echo "$zeile" | sed 's/\ //g' | grep -iq $1 && \
{
echo "$zeile" | ...
...
}
done
Das funktioniert zwar, ist aber ziemlich langsam.
Wenig verwunderlich. Pro Zeile aus Deinem Telefonbuch wird alles in
der Schleife (also mindestens 2 Prozesse) jedes Mal neu gestartet.
Dort liegt das Geschwindigkeitsproblem; ein grep in der gewünschten
Form würde daran nichts Grunsätzliches ändern.

Ich würde zunächst einmal den 'while read' hinter den grep verlegen,
so dass die Schleife nur für Treffer gestartet wird. Weder sed noch
grep müssen (soweit ich sehe) für jede Telefonbuch-Zeile neu gestartet
werden.

Einen grep, der Leerzeichen (in der Input-Datei[1]) ignoriert, kannst Du
Dir selbst basteln, indem Du sein Argument passend machst:

grep_arg="$(echo "$1" | sed 's/\([^ ]\)/\1 */g')"

und dann später »grep -i "$1"« gegen »grep -i "$grep_arg"«
austauschst. Im Vergleich zur Verlegung der Schleife ist der Zugewinn
aber vermutlich kaum der Mühe wert.

___
[1] Im Suchbegriff kommen ja offensichtlich keine Leerzeichen vor,
sonnst würde Dein obiges Programm gleich gar nicht laufen.
Martin Klaiber
2008-01-14 09:59:10 UTC
Permalink
Post by Heike C. Zimmerer
Einen grep, der Leerzeichen (in der Input-Datei[1]) ignoriert, kannst Du
grep_arg="$(echo "$1" | sed 's/\([^ ]\)/\1 */g')"
Das funktioniert bei mir nicht, weiß nicht warum. Aber mit

sed 's/./\0 */g'

geht es. Danke.
Post by Heike C. Zimmerer
[1] Im Suchbegriff kommen ja offensichtlich keine Leerzeichen vor,
Ja, das ist richtig.
Stefan Reuther
2008-01-13 15:05:39 UTC
Permalink
Post by Martin Klaiber
Ich suche ein grep (oder ähnliches tool), das whitespace ignorieren
kann. Zweck ist die Suche nach Telefonnummern, die Leerzeichen
enthalten können.
Beispiel: die Telefonnummer 1234567 wird oft in einer der folgenden
Bau doch die Regexps entsprechend um. Statt nach "1234567" suchst du
halt nach "1 *2 *3 *4 *5 *6 *7". Damit wäre das Whitespace-grep zum
Beispiel das hier:
----8<----
rx=$1
shift
grep "$(echo "$rx" | sed -e 's/./& */g' -e 's/ \*$//')" "$@"
----8<----


Stefan
Hubert Schmid
2008-01-13 15:24:05 UTC
Permalink
Post by Martin Klaiber
Ich suche ein grep (oder ähnliches tool), das whitespace ignorieren
kann. Zweck ist die Suche nach Telefonnummern, die Leerzeichen
enthalten können.
Beispiel: die Telefonnummer 1234567 wird oft in einer der folgenden
1 23 45 67
123 45 67
12 34 567
Alle sollen gefunden werden. Eine Möglichkeit wäre natürlich, im
Text einfach Leerzeichen innerhalb von Telefonnummer zu verbieten,
aber das schränkt die Lesbarkeit für Menschen ein, scheidet also
aus. Auch die Lösung, eine feste Schreibweise vorzuschreiben,
scheitert in der Regel am Faktor Mensch.
Eine Alternative ist, die Leerzeichen im regulären Ausdruck zu
berücksichtigen. Statt '1234' den regulären Ausdruck '1 *2 *3 *4'
verwenden. Den Suchausdruck kannst du dir auch automatisch
zusammenbauen lassen, beispielsweise mit sed.

Gruß, Hubert
--
Hubert Schmid - http://z42.de
Achim Peters
2008-01-13 15:43:14 UTC
Permalink
Post by Martin Klaiber
Ich suche ein grep (oder ähnliches tool), das whitespace ignorieren
kann. Zweck ist die Suche nach Telefonnummern, die Leerzeichen
enthalten können.
Beispiel: die Telefonnummer 1234567 wird oft in einer der folgenden
1 23 45 67
123 45 67
12 34 567
Alle sollen gefunden werden.
grep [0-9 ]+

So etwas in der Art?

HTH

Bye
Achim
Martin Klaiber
2008-01-14 09:54:37 UTC
Permalink
Post by Achim Peters
grep [0-9 ]+
So etwas in der Art?
Der Suchbegriff soll schon ausgewertet werden. Es geht um so etwas wie
die bekannte Rückwärtssuche bei Telefon-CDs.
Achim Peters
2008-01-14 13:03:43 UTC
Permalink
Post by Martin Klaiber
Post by Achim Peters
grep [0-9 ]+
So etwas in der Art?
Der Suchbegriff soll schon ausgewertet werden. Es geht um so etwas wie
die bekannte Rückwärtssuche bei Telefon-CDs.
Ach, Du suchst eine bestimmte Nummer, sorry.

Darf's auch perl sein, das lern ich gerade? Da ginge das z. B. so

perl -e 'while (<>) { $a=$_; s/ //g; print $a if (/123456789/); }' <
telefon.dat

Aber da gibt's bestimmt auch eine kryptischere Variante ... ;-)

Bye
Achim

Christian Weisgerber
2008-01-13 16:21:51 UTC
Permalink
Post by Martin Klaiber
Ich suche ein grep (oder ähnliches tool), das whitespace ignorieren
kann. Zweck ist die Suche nach Telefonnummern, die Leerzeichen
enthalten können.
So als erste Idee: egrep '([0-9] *)+'
Post by Martin Klaiber
cat telefon.dat | sort | while read zeile; do
echo "$zeile" | sed 's/\ //g' | grep -iq $1 && \
Das funktioniert zwar, ist aber ziemlich langsam. Weiß jemand, woran
das liegt, und wie man das verbessern könnte?
read liest zeichen(!)weise aus der Pipe. Viele Syscalls. Dazu mehrere
neue Prozesse je Zeile.
--
Christian "naddy" Weisgerber ***@mips.inka.de
Joern Abatz
2008-01-14 03:33:26 UTC
Permalink
Post by Martin Klaiber
cat telefon.dat | sort | while read zeile; do
echo "$zeile" | sed 's/\ //g' | grep -iq $1 && \
{
echo "$zeile" | ...
...
}
done
Schritt 1: eine Liste von Zeilennummern gewinnen,
Schritt 2: diese Zeilen anzeigen.

cat myfile | tr -d ' ' | grep -n 'pattern' | cut -d ':' -f 1 |
while read NUM ; do sed -n "${NUM}p" myfile ; done

Jörn
Martin Klaiber
2008-01-14 09:51:16 UTC
Permalink
Post by Joern Abatz
cat myfile | tr -d ' ' | grep -n 'pattern' | cut -d ':' -f 1 |
while read NUM ; do sed -n "${NUM}p" myfile ; done
Danke, funktioniert sehr gut, und ist ca. 20x schneller als mein
ursprünglicher Code.
Loading...