[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



Hallo,

On Tue, 3 Jan 2017 08:49:19 +0100
Jochen Spieker <ml@well-adjusted.de> wrote:

> 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.
(...)
> > aber andererseits ist performance-technisch wohl eher die Schleife an
> > sich das Problem.
> 
> Oder vielleicht das case-Statement? Das Pattern ist sicher teuer.
> 
(...)
> 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

Ja, hatte ich ja schon erwähnt, das hat mir am Anfang auch
Verständnisprobleme bereitet.
Habe das zum Testen mal in dieser Form laufen lassen:

for p in $PKGNAMES; do
    if [[ " $INSTALLED_PKGS " =~ " $p " ]] ; then
        PKGS="$PKGS $p"
    fi
done

Das dauert hier mit 1200 PKGNAMES ca. 1,92 Sek. gegenüber 1,96 Sek. mit
der case-Variante, ist also nur unwesentlich schneller und nagelt mich auf
bash fest, während die case-Variante in dash in 0.29 Sek. läuft.

In einer leicht modifizierten Form mit Wildcard:
for p in $PKGNAMES; do
    if [[ " $INSTALLED_PKGS " == *" $p "* ]] ; then
        PKGS="$PKGS $p"
    fi
done

dauert das ganze dann 2,10 Sek. in bash, der Unterschied (~9%) ist also
in der bash noch überschaubar.
Zum Spass hab ich das nochmal mit ksh getestet, dort ist der Unterschied
gewaltig, ca. 1,75 Sek. mit den Wildcards, 0,14 Sek. in der Variante ohne
(dann allerdings mit falschem Resultat :)

> 
> > (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.

Wenn man die ganzen "Paketlisten" auf einmal an grep (oder wie von
Christian vorgeschlagen uniq) weiterreicht, ist das bestimmt schneller,
aber dann muss ich wieder über die Argumentlänge nachdenken. Ich habe mir
mal eine Beschreibung zum Thema auf
http://www.in-ulm.de/~mascheck/various/argmax/
angeschaut und bin dann für mich zum Ergebnis gekommen, dass ich davon
besser die Finger lasse, ich habe damit nicht wirklich das Gefühl, dass
ich "weiss was ich tue" und möchte nicht nochmal in die gleiche Falle
tappen.

Ich versuche diesen Teil des Skripts auch eher im Kontext zu sehen, im
Skript läuft vorher ein "apt-get update", danach ein "apt-get -s dist-upgrade",
und letztlich sind die beiden wohl der engere Flaschenhals als dieser
Codeabschnitt, zumal in "lebensechten" Situationen die PKGNAMES Liste
wohl eher im 2- oder allenfalls niedrigen 3-stelligen Bereich liegt, was
das Performanceproblem dann doch deutlich entschärft.
Nebenbei, den Teil des Skripts der die Anzahl der verfügbaren Updates
ermittelt, habe ich 1:1 aus apticron kopiert, dort sieht die
entsprechende Passage so aus:

for p in $PKGNAMES; do
    if [ -z "`dpkg -s $p 2>/dev/null| grep '^Status: install ok installed'`" ] ; then
        PKGNAMES=`echo $PKGNAMES |sed "s/\(^\| \)$p\( \|$\)/ /g;s/^ //g"`
    fi
done

Damit ist man bei > 1000 Paketen schon gut im Minutenbereich unterwegs :-)
(und am Ende stimmen mitunter die Resultate nicht, weshalb ich
ehrlich gesagt überhaupt erst auf die Idee kam, mir dafür etwas
anderes zu überlegen).

Gruss

Michael


.-.. .. ...- .   .-.. --- -. --.   .- -. -..   .--. .-. --- ... .--. . .-.

Peace was the way.
		-- Kirk, "The City on the Edge of Forever", stardate
unknown


Reply to: