[linux-l] bash listen funktionen

Volker Grabsch vog at notjusthosting.com
So Mai 21 07:18:54 CEST 2006


On Sat, May 20, 2006 at 09:48:50PM +0200, Ivan F. Villanueva B. wrote:
> Kann man Arrays als Parameter für Funktionen benutzen ?

Auch wenn sich diese Frage schon erledigt hat: Ich persönlich würde in
der Bash erst gar keine Listen nehmen. Außer vielleicht für für
Argumente.

Das meiste geht IMHO leichter, wenn man die Daten als Stream lässt, und
dann grep, sed oder awk rüberjagt, mit denen diese "listenartigen"
Operationen viel leichter zur Hand gehen, als wenn man das zu Fuß
("elementweise") in Shellscript ausdrückt.

> Wie bekomme ich das letzte Element eines Arrays? Kann man Zeilen als
> Elemente eines Arrays zuweisen (array=`ls` ; array[1]) ?

Mit sed:

    ls | sed -n 1p

oder mit head:

    ls | head -n 1

oder ganz kurz:

    ls | head -1


> adjacent() {
>     active_tag=`cat /mnt/wmii/view/name`
>     found=""
>     for i in $list ; do
>         if [ "$found" == "true" ]; then
>             echo -n view "$i" >> /mnt/wmii/ctl
>             return
>         fi
>         if [ "$i" == "$active_tag" ]; then
>             found="true"
>         fi
>     done


Du willst also alle Zeilen, die nach $active_tag kommen, raussuchen.
Eine Variante ist:

    sed -n "/^$active_tag$/,$ p"

dies liefert alle Zeilen *ab* der $active_tag - Zeile. Willst du diese
Zeile auch noch ausschließen, hast du mehrere Möglichkeiten. Die
kürzeste ist wahrscheinlich die, alle Zeilen *bis* zum active_tag
zu nehmen (0,/.../) und diese Auswahl zu negieren (!):

    sed -n "0,/^$active_tag$/ ! p"

Dann möchtest du es nicht direkt ausgeben (p), sondern ein "view "
davorstellen, dies entspricht der Regex:

    s/^/view /

Das heißt:

    sed -n "0,/^$active_tag$/ ! s/^/view / p"


>     # Nur um das erste Element rauszubekommen. Geht es anders ?
>     for i in $list ; do 
>         echo -n view "$i" >> /mnt/wmii/ctl
>         return
>     done

Die erste Zeile herauszusuchen geht mit sed so:

    sed -n 1p

(oder auch
    sed -n "1 p"
 d.h. statt der Regex schreibst du einfach die Zeilennummer)

Aus einem Stream, den du wiederverwenden möchtest, die erste
Zeile auslesen geht mit "read":

    read first
    echo "$first"


Ich würde deine "adjacent" also so schreiben:

adjacent() {
    active_tag=`cat /mnt/wmii/view/name`
    read first

    sed -n "0,/^$active_tag$/ ! s/^/view / p" \
    >> /mnt/wmii/ctl

    echo -n "view $first" >> /mnt/wmii/ctl
}

Das mit dem festhalten der ersten Zeile kann man auch noch in
sed realisieren, da sed einen kleinen Puffer zur Verfügung stellt:

    sed -n "1 h ; 0,/^test$/ ! p ; $ {x;p}"

Die erste Zeile (1) wird in den Puffer geschrieben (h), und bei der
letzten Zeile ($) wird der Puffer in den Ausgabepuffer getauscht (x)
und dann ausgegeben (p).


Dann sollte man das mit dem "view" aber separat regeln:

adjacent() {
    active_tag=`cat /mnt/wmii/view/name`

    sed -n "1 h ; 0,/^$active_tag$/ ! p ; $ {x;p}"  |
    while read i; do
        echo "view $i" >> /mnt/wmii/ctl
    done
}


Oder wenn man ausschließlich "sed" benutzen will:

adjacent() {
    active_tag=`cat /mnt/wmii/view/name`

    sed -n "1 h ; 0,/^$active_tag$/ ! p ; $ {x;p}"  |
    sed "s/^/view /" >> /mnt/wmii/ctl
}


Das prev() und next() geben dann Streams an adjacent(), und pipelines
sind natürlich effizienter als im Speicher gehaltene Listen:

> next() {
>     list=`cat /mnt/wmii/tags`
>     adjacent 
> }

wird zu:

next() {
   cat /mnt/wmii/tags | adjacent 
}


> prev() {
>     list=`cat /mnt/wmii/tags | tac`
>     adjacent 
> }

wird zu:

next() {
   tac /mnt/wmii/tags | adjacent 
}



BTW, wie hast du es eigentlich gelöst (mit $*, etc.) ?



Viele Grüße,

    Volker

-- 
Volker Grabsch
---<<(())>>---
Administrator
NotJustHosting GbR



Mehr Informationen über die Mailingliste linux-l