[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: [gelöst]Re: /bin/sh: prüfen ob String1 "Wort" aus String2 enthält



Michael Lange:
>> Jochen Spieker <ml@well-adjusted.de> wrote:
> 
>>> Doch, in der asymptotischen Betrachtung schon. :) Du baust den
>>> String 
>>> PKGS pro Paket neu (n mal) und dabei wird er immer länger. Der erste 
>>> Paketname wird n-1 mal kopiert, der zweite n-2 und so weiter. Das ist
>>> einfach ein schlechter Algorithmus. Die Laufzeit steigt
>>> überproportional zur Länge der Paketliste. Sowas will man
>>> grundsätzlich vermeiden.
> 
> Ist mir im Prinzip natürlich klar, der naheliegende Ansatz wäre eher,
> nicht in INSTALLED_PKGS vorhandene Einträge aus PKGNAMES zu entfernen,
> allerdings geht das mit der Shell selbst nicht (soweit ich weiss
> zumindest), und eine Pipe mit sed oder so zu benutzen wird auch bei
> relativ wenigen zu eliminierenden Paketen schnell sehr ineffizient.

Dafür verwende ich gerne grep. Wenn INSTALLED_PKGS und PKGNAMES in
entsprechend benannten Dateien sind (ein Paket pro Zeile, Sortierung
egal):

grep -v -f INSTALLED_PKGS PKGNAMES

-v gibt Dir *nicht* matchende Zeilen aus, -f $file liest die Patterns
aus $file. In diesem konkreten Fall würde ich auch noch -F ("fixed
strings") entfernen. Das schaltet den Regex-Parser in grep aus und macht
es deutlich schneller.

> Ich habe jetzt noch testweise mal ausprobiert, wie gross die Verzögerung
> durch das wiederholte verändern von PKGS ist. Die for-Schleife lief
> (sowohl in dash als auch bash) jew. ca. 10% schneller, wenn die
> entspr. Zeile auskommentiert wird (die Schleife also durchläuft ohne
> wirklich etwas zu tun). Zweifellos nicht schön, aber andererseits ist
> performance-technisch wohl eher die Schleife an sich das Problem.

Oder vielleicht das case-Statement? Das Pattern ist sicher teuer.

> Ok, durch herumprobieren herausgefunden, die Anfühungzeichen um $p
> entfernen und die Leerzeichen durch Backslash maskieren scheint die
> Posix-konforme Variante zu sein:
> 
> for p in $PKGNAMES; do
>     case " $INSTALLED_PKGS " in
>         *\ $p\ *)
>            PKGS="$PKGS $p";;
>     esac
> done

Warum nimmst Du überhaupt case, wenn Du nur einen Fall hast? Mir
erscheint die Prüfung auch von der Logik her irgendwie falschrum. Du
könntest auch so prüfen:

if [[ "$INSTALLED_PKGS" =~ "$p" ]] ; then
    echo huhu;
fi

> (falls jemand ein gutes Tutorial kennt, aus dem man solche Dinge lernen
> kann, wäre ich dankbar für einen Link :)

Leider nein. Das oben dürfte auch bash-spezifisch sein. Portabel würde
ich das mit echo und grep lösen. Würde mich nicht wundern, wenn das
besser performt, als das Pattern mit Wildcards vorne und hinten.

J.
-- 
I believe there is a world of wealth, fashion and elegance that will be
forever denied to me.
[Agree]   [Disagree]
                 <http://archive.slowlydownward.com/NODATA/data_enter2.html>

Attachment: signature.asc
Description: Digital signature


Reply to: