LX-SCR-INFO-funkties
Updated 7/27/10 00:36

funkties

Als je regelmatig scripts schrijft, begin je te kopiëren van scripts die je reeds geschreven hebt. Dat is niet slecht, maar wel gevaarlijk. Je zou per ongeluk het reeds bestaande script wel eens kunnen verminken. Bovendien is het mogelijk dat je tijdens het 'cut and paste' proces een paar regels of karakters vergeet. Tenslotte werkt niet alle code zomaar overal.

Voor dit probleem is een function bibliotheek de perfecte oplossing.

Maar bash functions kun je ook gebruiken om je script gewoon overzichtelijker te maken.
En zodra je twee keer dezelfde code in één script gebruikt, spaar je tijd en plaats met functions.

Functions moet je plaatsen voor ze worden aangeroepen. Verder is er geen belemmering. Het is echter makkelijker en overzichtelijker alle functies te declareren aan het begin van een script.

  1. syntax

    function <functionname> () {
    <commando's>
    }

    Je kan een function beginnen met function; () is dan niet nodig.
    Je kan een function beginnen met zijn naam;
    het keyword function is dan niet nodig, de () wel.

    In deze cursus gebruik ik altijd de vorm: function <naam> { <commando's> }
    Er zijn dus nergens ().

  2. voorbeeld

    In dit voorbeeld wordt er een function aangeroepen die de laatste 5 regels van de /var/log/messages op scherm brengt.

    #!/bin/bash
    #
    # whatwedo
    #
    function showlog {
        clear
        tail -n 5 /var/log/messages
    }
    # zolang root niet is ingelogd blijft de volgende until lus draaien
    until w | grep "root"
    do
        showlog
        sleep 5
    done

  3. parameters

    Funkties in bash werken graag met parameters. We herwerken het vorige voorbeeld ...

    #!/bin/bash
    #
    # whatwedo2
    #
    function showlog2 {
    # $1 = logfile to display
    # $2 = aantal regels
    # $3 = refresh time
        clear
        tail -n $2 $1
        sleep $3
    }
    function timestamp {
        echo $(date +"%Y%m%d%H%M")
    }
    # zolang root niet is ingelogd blijft de volgende until lus draaien
    until w | grep "root"
    do
        showlog2 /var/log/messages 10 2
    done
    printf "root has logged in :"
    timestamp

  4. library

    Maak een file in je bin directory met als naam functions.lib. Deze file moet niet executable zijn, wel leesbaar vanaf je script.
    Stop in functions.lib al je functions die je overal wil kunnen gebruiken.
    Lees die dan vanaf je script
    De naam en het path van de library kies je zelf!

    functions.lib:
    function showlog2 {
    # $1 = logfile to display
    # $2 = aantal regels
    # $3 = refresh time
        clear
        tail -n $2 $1
        sleep $3
    }
    function timestamp {
        echo $(date +"%Y%m%d%H%M")
    }

    whatwedo3:
    #!/bin/bash
    #
    # whatwedo3
    #
    # nu lezen we de function library in met het dot commando
    . ~/bin/functions.lib
    #
    # zolang root niet is ingelogd blijft de volgende until lus draaien
    until w | grep "root"
    do
        showlog2 /var/log/messages 10 2
    done
    printf "root has logged in :"
    timestamp

  5. variabelen

    Variabelen die gebruikt worden binnen een function zijn lokaal en wijzigen script variabelen met dezelfde naam niet:

    #!/bin/bash
    #
    # fvar: een educatief script
    # dat het gebruik van variabelen in functies toont

    #
    stad=Hasselt
    provincie=Limburg
    function mixup {
    stad=Gent
    provincie=OVL
    echo $stad $provincie
    }
    echo script: $stad $provincie
    echo function: $(mixup)
    echo script: $stad $provincie
    echo function: $(mixup)

    Met als output:

    $ fvar
    script: Hasselt Limburg
    function: Gent OVL
    script: Hasselt Limburg
    function: Gent OVL

  6. recursieve functions

    Recursie is het oproepen van zichzelf in een routine.

    Bekijk even het volgende probleem:

    Als ik een kopieeropdracht uitvoer van een gigantische file, kan ik de vooruitgang volgen op een andere terminal met het commando ls -l. Dat moet ik dan regelmatig intikken. Als ik mijn leven makkelijker zou willen maken zou ik het volgende script kunnen construeren:

    #!/bin/bash
    #
    # showls: toont de directory van parameter $1
    #
    clear
    ls -l $1
    sleep 5
    showls

    Maar, een script dat zichzelf aanroept, maakt telkens nieuwe processen aan, met als gevolg dat de computer vroeger of later vastloopt.
    En dat is een ramp voor mijn kopieeropdracht, met veel tijdverlies, of erger, tot gevolg.

    Functions hebben dit probleem niet, omdat ze niet telkens een nieuw bash proces lanceren, maar de stack van bash kan nog wel overlopen!!! Als de stack overflowt heeft dat echter alleen effect op die bash die mijn script beheert. De andere processen kunnen gewoon door blijven lopen, of toch niet :-) ? Zoek dat misschien zelf eens op!

    Het volgende script kan dus wel veel langer doorlopen dan het vorige:

    #!/bin/bash
    #
    # fshowls: toont de directory van parameter $1
    #
    function showls {
    clear
    ls -l $1
    sleep 5
    showls
    }
    showls $1

    De eenvoudigste oplossing voor het hogere probleem is echter het commando watch.

    $ watch -n5 ls -l

  7. export

    Je kan functions exporteren en ze dan gebruiken aan de bash prompt. functions hebben wat meer mogelijkheden dan aliassen. Een dergelijke function inclusief export plaats je het best in je .bashrc

    fname {
    echo "Foo"
    }
     
    export -f fname


  8. oefeningen

    1. Maak een function met als naam ohce (echo omgekeerd) die al zijn argumenten omgekeerd afdrukt. Gebruik dit in een script. (tip: man rev)

    2. Bekijk het voorbeeld "apester" in het hoofdstuk "parameters" opnieuw.

    3. Maak twee functions: leftstr en rightstr die een string respectievelijk links en rechts afknippen ter hoogte van karakternummer. string en karakternummer zijn de parameters waarmee de functions worden opgeroepen.
      Illustreer je funktie met een voorbeeldscript.