[Bash] User input validatie, wat is het meest clean?

Pagina: 1
Acties:

  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Allereerst, ik ben redelijk beginner in scripten/programmeren :P Ik ben nu een script aan het maken met een aantal ja/nee vragen. Ik wil de userinput valideren. Nu kan dat op verschillende manieren die ik met zoeken heb gevonden:

• while $value != yes || no
do
vraag
done
Nadeel: geen user feedback bij foutieve input. Ook weer alle code bij elke vraag.

• na de vraag:
case $value in
yes || no ) echo 'succes'
*) echo 'fail'
Nadeel: wel user feedback maar stelt de vraag niet opnieuw

• Nog een oaar zeer ingewikkelde validatiemethodes gevonden die ik niet echt relevant vind voor mijn code.

• Nu heb ik een functie voor yesno vragen die valideert. De functie heeft een $input en $result. Het ziet er zo uit:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function checkYesNo() {
    
    shopt -s nocasematch
    
    if $testYesNoVar == [[^(yes)|[yn]|(no)$]]
        then $testResult == 1;
        
        else $testResult == 0
            echo 'Invalid input, try again. Press "y" for "yes" or "n" for "no"';

}


while [[ $testResult == 0 ]]
do
    echo "Install application?"
    read installapp

    $testYesNoVar = $installapp
    checkYesNo

    if [[$testResult == 1 ]]
        then $testResult = 0        #reset testresult
            break;
done

Ik heb hiermee bij meerdere vragen checken gereduceerd naar 1 keer code in de functie, er is een loop en user feedback. Toch voelt de validatie nog omslachtig aan met redelijk wat code bij elke vraag. Kan dit efficienter?

Edit: en terwijl ik hier ijsbeer tijdens het tandenpoetsen bedenk ik zelf alweer iets :P

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function checkYesNo() {
    
    shopt -s nocasematch
    
    if $testYesNoVar == [[^(yes)|[yn]|(no)$]]
        echo 'Thanks for your input.;
        
        else echo 'Invalid input, try again. Press "y" for "yes" or "n" for "no"'
            $function;

}


function installAppQuestion() {
    
    echo "Install app?"
    read installapp

    $testYesNoVar = $installapp
    $function = 'installAppQuestion'
    checkYesNo;
}


Scheelt per vraag 4 regels code :)

[ Voor 24% gewijzigd door JT op 16-09-2015 23:11 ]

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • deadinspace
  • Registratie: Juni 2001
  • Nu online

deadinspace

The what goes where now?

Een paar tips:
  • Maak je checks en je prompts voor de antwoorden niet te ingewikkeld; het is bijvoorbeeld bij dit soort interfaces gebruikelijk om bij een ongeldig antwoord gewoon de vraag te herhalen.
  • Probeer zoveel mogelijk van wat je moet herhalen in je function te doen, zoals bijvoorbeeld het stellen van de vraag. Je kunt argumenten meegeven aan functies!
  • Je kunt een functie vrij simpel gebruiken als check in een 'if', als je je functie 0 of 1 laat returnen.
Het zou zo moeten kunnen dat je in je gewone code eigenlijk alleen één if met je functie-aanroep nodig hebt, en dat je functie de rest doet ;)

  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Ik meende dat je in bash geen argumenten aan je functie kunt meegeven in de () :? Dus dan zou het moeten zoals ik het doe toch?

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • gekkie
  • Registratie: April 2000
  • Laatst online: 12-10 19:01
Klopt .. in bash moet het anders dan in de gemiddelde taal, zie bijvb:
http://bash.cyberciti.biz...arguments_into_a_function

Eigenlijk gewoon de syntax van een willekeurig ander commando/script aanroepen met arguments.
(en dus opzich ook wel weer logisch als je het eenmaal weet)

[ Voor 39% gewijzigd door gekkie op 16-09-2015 23:35 ]


  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
gekkie schreef op woensdag 16 september 2015 @ 23:34:
Klopt .. in bash moet het anders dan in de gemiddelde taal, zie bijvb:
http://bash.cyberciti.biz...arguments_into_a_function

Eigenlijk gewoon de syntax van een willekeurig ander commando/script aanroepen met arguments.
(en dus opzich ook wel weer logisch als je het eenmaal weet)
Ok, dan zou je dus uitkomen op

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function checkYesNo() {
    
    shopt -s nocasematch
    
    if $1 != [[^(yes)|[yn]|(no)$]]
        then  echo 'Invalid input, try again. Press "y" for "yes" or "n" for "no".'
              $2;

}


function installAppQuestion() {
    
    echo "Install app?"
    read installapp

    checkYesNo $installApp installAppQuestion;
}


Cool, nog een stukje korter :)

Edit: nog korter gemaakt door feedback bij juist antwoord eruit te slopen. De feedback daarvan is in feite dat je naar de volgende vraag gaat.

[ Voor 10% gewijzigd door JT op 17-09-2015 09:32 ]

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 14:15
Wil je die prompt (echo) en read voor andere vragen anders doen? Anders zou ik dat (en het loopen) naar die functie verplaatsen en dan hoef je alleen maar iets als
Bash:
1
2
3
if askYesNo "Install app?"; then
    # install
fi
te doen. Moet je dus wel 0 of 1 returnen zoals deadinspace zei. Met jouw laatste versie moet je na het aanroepen van checkYesNo zelf nog een keer een vergelijking doen om te weten of je nu wel of niet moet installeren.

btw: omdat je geen quotes om $installApp zet in de aanroep van checkYesNo gaat dat mis als iemand meer dan één woord invoert.

  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Mijn script stelt eerst een aantal vragen, die gevalideerd worden, later wordt er geinstalleerd. Dus zo:
Vraag 1
- Validatie
Vraag 2
- Validatie
Vraag 3
- Validatie

Vraag 1 = ja dan install 1
Vraag 2 = ja dan install 2
Vraag 3 = ja dan install 3

Ik snap niet helemaal wat je nu bedoelt met je suggestie :)

En ja mijn script was nog niet optimaal, die heb ik vanochtend verder geoptimaliseerd:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function checkYesNo() {
    
    shopt -s nocasematch
    
    if ! [[ $1 =~ ^(yes)|[yn]|(no)$ ]] 
        then echo 'Invalid input, try again. Press "y" for "yes" or "n" for "no"'
             $2;
fi
}


function installAppQuestion() {
    
    echo "Install app?"
    read -r installapp
    
    checkYesNo "$installapp" installAppQuestion;
}

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 14:15
JT schreef op donderdag 17 september 2015 @ 11:10:
Mijn script stelt eerst een aantal vragen, die gevalideerd worden, later wordt er geinstalleerd.
Oké, maar het idee om een standaardrepresentatie voor yes of no te gebruiken, blijft van toepassing. Je validatie is zo aardig om verschillende vormen van yes en no te accepteren. Met wat je nu hebt, moet je, als het tijd is om te gaan installeren, weer diezelfde regex gaan matchen. De validatiefunctie kan het resultaat opslaan/returnen en dan dus 0 (of evt. "yes") produceren voor zowel "YEs" als "y".
Ik snap niet helemaal wat je nu bedoelt met je suggestie :)
Eigenlijk gewoon wat deadinspace al zei, maar ik gaf voor het "gebruik als check in een if" een codevoorbeeldje en gaf nog iets concreter aan wat je nog naar de yesno-functie kon verplaatsen zodat je het niet voor elke vraag hoeft te herhalen (nl. die echo en read + loop), tenzij dat iets is dat erg verschilt per vraag.

Als je echt alleen een lijstje met apps moet aflopen, kun je ook zoiets doen met arrays:
Bash:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apps_available=(app1 app2)
apps_to_install=()

# 1: stel vragen (incl. validatie)
for app in "${apps_available[@]}"; do
    if askYesNo "Install $app?"; then
        apps_to_install+=("$app")
    fi
done

# 2: installeer
for app in "${apps_to_install[@]}"; do
    # install $app
done

Dan is askYesNo() (=huiswerk :p edit: niet meer, zie hieronder) dus nog steeds een uitgebreidere versie van jouw checkYesNo() die behalve de check ook de vraag print en het antwoord leest en dit blijft doen tot het antwoord geldig is en dan 0 of 1 returnt. Dit houdt het kort, maar als je per app meer variatie in de vraag- of installatiestap wilt, zul je toch iets meer moeten uittypen.

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Ik doe meestal iets in deze trant:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function yesno() {
  local ANSWER
  while true;
  do
    echo "$@ [Y/n]?"
    read ANSWER
    case $ANSWER in
      y|Y|"")
        return 0
        ;;
      n|N)
        return 1
        ;;
      *)
        echo "Unknown option $ANSWER"
        ;;
    esac
  done
}

Ik heb over tijd wel wat varianten geimplementeerd, maar de basis komt op hetzelfde neer.

[ Voor 37% gewijzigd door H!GHGuY op 17-09-2015 12:21 ]

ASSUME makes an ASS out of U and ME


  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Food for thought zodra ik thuis ben :P Arrays weet ik niet zoveel over maar is nog genoeg over te vinden. Het concept snap ik maar moet ik nog even tegen mijn totale script aanhouden. Script doet ook nog iets met een user aanmaken, nieuwe file met text aanmaken dan wel pipen naar een bestaande file. Het is wel een goed idee denk ik :D Ga er zeker naar kijken.

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


Acties:
  • 0 Henk 'm!

  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Inmiddels gelezen over arrays dus ik kan verder. De code van H1ghguy snap ik ook :)
Raynman schreef op donderdag 17 september 2015 @ 12:17:
Als je echt alleen een lijstje met apps moet aflopen, kun je ook zoiets doen met arrays:
Bash:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apps_available=(app1 app2)
apps_to_install=()

# 1: stel vragen (incl. validatie)
for app in "${apps_available[@]}"; do
    if askYesNo "Install $app?"; then
        apps_to_install+=("$app")
    fi
done

# 2: installeer
for app in "${apps_to_install[@]}"; do
    # install $app
done

Dan is askYesNo() (=huiswerk :p edit: niet meer, zie hieronder) dus nog steeds een uitgebreidere versie van jouw checkYesNo() die behalve de check ook de vraag print en het antwoord leest en dit blijft doen tot het antwoord geldig is en dan 0 of 1 returnt. Dit houdt het kort, maar als je per app meer variatie in de vraag- of installatiestap wilt, zul je toch iets meer moeten uittypen.
Ik snap
code:
1
if askYesNo "Install $app?";
misschien nog niet helemaal. Betekent dat eigenlijk "als output van functie askYesNo = true" ?

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


Acties:
  • 0 Henk 'm!

  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 14:15
JT schreef op zondag 20 september 2015 @ 13:36:
Ik snap
code:
1
if askYesNo "Install $app?";
misschien nog niet helemaal. Betekent dat eigenlijk "als output van functie askYesNo = true" ?
Niet output, maar return value (of bij een extern commando vaak exitstatus genoemd). Dat kun je voor een pure functie (wiskundig gezien) wel output noemen, maar dat is verwarrend in deze context. Ter illustratie, checken of functie() letterlijk de string "true" output op standard out, zou zoiets zijn:
Bash:
1
if [[ $(functie) == true ]]; then

En om het plaatje dan nog wat completer te maken: hier is [[ ]] een speciale constructie die ook 0 of 1 produceert na het evalueren van de expressie tussen die haken. Oorspronkelijk had je een programma genaamd "[" (één haakje; aka "test") voor dit soort expressies, maar tenzij je zoveel mogelijk shells wilt ondersteunen, is de ingebouwde variant met dubbele haken gebruiksvriendelijker.

Maar de functie van H!GHGuY kun je dus op die manier gebruiken: die returnt 0 (succes of true) voor yes en 1 voor no. De quotes om de vraag kun je dan evt. weglaten in de aanroep, omdat met "$@" alle argumenten worden geprint.

  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Ik heb niet allemaal apps die geinstalleerd moeten worden, er worden ook acties uitgevoerd (cat, sed etc.) Dus nu heb ik het als volgt bedacht:

- Alle vraagfuncties heten <actie><app>Question
- Alle uitvoerende functies heten <actie><app>
Vervolgens:
code:
1
2
3
4
5
6
7
8
9
10
11
function checkYesNo() {
    
    shopt -s nocasematch
    
    if ! [[ $1 =~ ^(yes|[yn]|no)$ ]] 
        then echo 'Invalid input, try again. Press "y" for "yes" or "n" for "no"'
             $2;
        else $2=${2/Question/}
            actions+=($2)
fi
}

Nu hou ik een array over met allemaal elementen met de naam van de functie die uitgevoerd moet worden :) Scheelt per uitvoer weer een test én de niet-uitgevoerde functies hoeven ook niet getest te worden. Het lijkt mij als beginner een leuk gevonden oplossing, alhoewel het strippen van de variabele wellicht niet ideaal is. Het is wel korter qua code. Wellicht zou ik de elementen moeten koppelen aan de functie middels een for <element> in <array> do <actie>?

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Ik ben nu toch aan het twijfelen, zal ik het zo doen:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function checkYesNo() {
    
    shopt -s nocasematch
    
    if ! [[ $1 =~ ^(yes|[yn]|no)$ ]] 
        then echo 'Invalid input, try again. Press "y" for "yes" or "n" for "no"'
             $2;
        elif [[ $2 =~ ^(yes|y)$ ]] 
              then $2=${2/Question/}
            actions+=($2);
fi
}

echo ${actions[@]}


Of

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function checkYesNo() {
    
    shopt -s nocasematch
    
    if ! [[ $1 =~ ^(yes|[yn]|no)$ ]] 
        then echo 'Invalid input, try again. Press "y" for "yes" or "n" for "no"'
             $2;
        elif [[ $2 =~ ^(yes|y)$ ]] 
            then actions+=($2)
fi
}

for $a in ${actions[@]};
    do installa
done

for $b in ${actions[@]};
    do installb
done

for $c in ${actions[@]};
    do runc
done


Wellicht is de tweede beter te lezen en netter omdat je het omzetten van de variabele naar een actie allemaal op 1 plek in de code doet? Aan de andere kant maakt het de code wel weer een stukje langer...

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

JT schreef op donderdag 24 september 2015 @ 12:23:
Wellicht is de tweede beter te lezen en netter omdat je het omzetten van de variabele naar een actie allemaal op 1 plek in de code doet? Aan de andere kant maakt het de code wel weer een stukje langer...
Dit is al de 2de keer dat het me opvalt, maar wat is je fixatie op korte code?
De metriek is leesbare en onderhoudbare code. In al te veel gevallen voldoet kort daar niet aan.

Zoals met alles: zo kort mogelijk maar niet korter.

ASSUME makes an ASS out of U and ME


  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
H!GHGuY schreef op donderdag 24 september 2015 @ 17:36:
[...]


Dit is al de 2de keer dat het me opvalt, maar wat is je fixatie op korte code?
Ik wil geen onnodige code. Onnodig betekent voor mij: ten koste van leesbaarheid, ten koste van semantiek, ten koste van onderhoudbaarheid en/of ten koste van performance.
Zoals met alles: zo kort mogelijk maar niet korter.
Ja precies, dat is een balans. En door mijn totale onervarenheid weet ik nu niet zeker of de balans beter is in oplossing 1 of 2. Maar inmiddels neig ik naar 2. Daar heb je bij elkaar staan welke variabele bij welke functie staat, waardoor het ook makkelijker te wijzigen is (beter onderhoudbaar) en je zet een variabele niet in als aanroep van een functie (lijkt me semantisch beter?).

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 14:15
Probeer dan iets meer met onze tips te doen of doe wat je zelf denkt dat goed is, maar werk het eerst wat verder uit totdat het wat duidelijker is welke delen repetitief, moeilijk te wijzigen of wat dan ook zijn. Je zegt zelf dat je een beginner bent; je leert waarschijnlijk meer als je het eerst minder mooi oplost en dan stapsgewijs de boel verbetert.

Bij optie 1 doe je nog niets met $actions (behalve echo) en bij optie 2 staan wat vreemde for-loops. Maar los van die incomplete code buiten de functie (die ook nog nergens aangeroepen wordt) is het enige verschil dat bij optie 1 de suffix "Question" verwijderd is van alle elementen in de array. Bij die tweede versie kun je
Bash:
1
echo ${action[@]%Question}
doen en je hebt hetzelfde resultaat als bij de eerste (dit toont meteen een andere vorm van parameter expansion die specifiek bedoeld is voor dit soort operaties i.p.v. de generieke vervanging die jij gebruikte). Of andersom, gebruik
Bash:
1
${action[@]/%/Question}
en je hebt alle namen weer met "Question" erachter. Dat is geen wezenlijk verschil.

Ik zei eerder "vreemde for-loops" en ik vraag me af je wel begrepen hebt hoe "for" werkt, want het lijkt een beetje alsof je, voor drie (namen van) acties (of vragen), opgeslagen in $a, $b en $c, wilt kijken of die in de array zitten om zo conditioneel de acties installa, installb en runc uit te voeren, maar dan moet je gewoon een if hebben met een subscript op die array parameter.

[ Voor 22% gewijzigd door Raynman op 24-09-2015 19:50 ]


  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Raynman schreef op donderdag 24 september 2015 @ 19:40:
Probeer dan iets meer met onze tips te doen of doe wat je zelf denkt dat goed is
Ik doe m'n best :|
maar werk het eerst wat verder uit totdat het wat duidelijker is welke delen repetitief, moeilijk te wijzigen of wat dan ook zijn. Je zegt zelf dat je een beginner bent; je leert waarschijnlijk meer als je het eerst minder mooi oplost en dan stapsgewijs de boel verbetert.
Daar ben ik mee bezig; m'n script is praktisch af op dit stuk na. Vandaar mijn vragen.
Bij optie 1 doe je nog niets met $actions (behalve echo) en bij optie 2 staan wat vreemde for-loops. Maar los van die incomplete code buiten de functie (die ook nog nergens aangeroepen wordt) is het enige verschil dat bij optie 1 de suffix "Question" verwijderd is van alle elementen in de array. Bij die tweede versie kun je
Bash:
1
echo ${action[@]%Question}
doen en je hebt hetzelfde resultaat als bij de eerste (dit toont meteen een andere vorm van parameter expansion die specifiek bedoeld is voor dit soort operaties i.p.v. de generieke vervanging die jij gebruikte). Of andersom, gebruik
Bash:
1
${action[@]/%/Question}
en je hebt alle namen weer met "Question" erachter. Dat is geen wezenlijk verschil.
Ok, ik dacht dat je met die echo de waarde in het script aanroept, hetzelfde als wanneer je die waarde letterlijk in het script typt. En dank voor de andere vorm van parameter expansion.
Ik zei eerder "vreemde for-loops" en ik vraag me af je wel begrepen hebt hoe "for" werkt, want het lijkt een beetje alsof je, voor drie (namen van) acties (of vragen), opgeslagen in $a, $b en $c, wilt kijken of die in de array zitten om zo conditioneel de acties installa, installb en runc uit te voeren, maar dan moet je gewoon een if hebben met een subscript op die array parameter.
Ik ga eens uitzoeken wat dat subscript is (het deel wat je tussen de blokhaken plaatst achter de arraynaam begrijp ik, wat ik er verder nog meer mee kan zoek ik uit).

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 14:15
JT schreef op donderdag 24 september 2015 @ 21:29:
[...]

Daar ben ik mee bezig; m'n script is praktisch af op dit stuk na.
Maar daar zien we niks van. Als je alleen de inhoud van de actiefuncties bedoelt (of zaken die nog minder met dit stuk te maken hebben), hoeft dat ook niet, maar enkele tips/opmerkingen in dit topic waren er ook op gericht dit stukje (qua interface) vriendelijker te maken voor de rest van het script die deze functie aan moet roepen en voor zover ik kan zien heb je daar niets mee gedaan. Doe je nu bijv. vaak eenzelfde soort read-aanroep of heb je dat stuk nog niet geschreven? (je kunt dit als een retorische vraag beschouwen)

Ga gewoon lekker verder knutselen met de bash manual of iets minder technische tutorials ernaast (mischien http://www.tldp.org/LDP/abs/html/index.html) en vergeet ook niet een terminal erbij te houden om dingen uit te proberen. Succes.

  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Heb nu gevonden dat het subscript hetzelfde is als de index van een array. Morgen eens naar kijken :)
Raynman schreef op donderdag 24 september 2015 @ 21:48:
[...]
Maar daar zien we niks van. Als je alleen de inhoud van de actiefuncties bedoelt (of zaken die nog minder met dit stuk te maken hebben), hoeft dat ook niet, maar enkele tips/opmerkingen in dit topic waren er ook op gericht dit stukje (qua interface) vriendelijker te maken voor de rest van het script die deze functie aan moet roepen en voor zover ik kan zien heb je daar niets mee gedaan. Doe je nu bijv. vaak eenzelfde soort read-aanroep of heb je dat stuk nog niet geschreven? (je kunt dit als een retorische vraag beschouwen)

Ga gewoon lekker verder knutselen met de bash manual of iets minder technische tutorials ernaast (mischien http://www.tldp.org/LDP/abs/html/index.html) en vergeet ook niet een terminal erbij te houden om dingen uit te proberen. Succes.
Ik heb jouw voorbeeld gebruikt als inspiratie voor mijn functie omdat er in mijn script 2 dingen worden geinstalleerd en 3 acties worden uitgevoerd waarbij niet iets wordt geinstalleerd en de vraag is ook anders. Daarom heb ik deze aangepast. Of zou je dan jouw suggestie voor deze 2 installs gebruiken en weer wat anders schrijven voor de andere 3 vragen? Het gaat om 2 installs, 1 keer user aanmaken en 2 keer file aanmaken of sed/cad afhankelijk van of de file er al is.

[ Voor 8% gewijzigd door JT op 24-09-2015 22:18 ]

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 14:15
Je kunt dit:
JT schreef op woensdag 23 september 2015 @ 11:49:
Dus nu heb ik het als volgt bedacht:

- Alle vraagfuncties heten <actie><app>Question
- Alle uitvoerende functies heten <actie><app>
waarbij installaties dus gewoon een specifiek type actie zijn, prima combineren met mijn opzetje:
Bash:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
actions_available=(foo bar)
actions_to_run=()

# 1: stel vragen
for action in ${actions_available[@]}; do
    if ${action}_question; then
        actions_to_run+=($action)
    fi
done

# 2: voer acties uit
for action in ${actions_to_run[@]}; do
    $action
done

Wij vermoedden echter dat je dan zoiets krijgt (met steeds yesno() van H!GHGuY):
Bash:
1
2
3
4
5
6
7
fooQuestion() {
    yesno Install app?
}

barQuestion() {
    yesno Perform action X?
}

De bijbehorende foo() en bar() (die de installatie, resp. andere actie "X" uitvoeren) zijn dan dus wel verschillend, maar het enige dat bij de *Question-functies verschilt is de vraag zelf. Met jouw checkYesNo() zou er nog meer dubbele code zijn:
Bash:
1
2
3
4
5
6
fooQuestion() {
    # alternatief voor echo: gebruik prompt optie van read
    read -p "Install app? [y/n] " answer
    checkYesNo answer fooQuestion
}
# barQuestion hetzelfde behalve "install app" en met "bar" ipv "foo" op laatste regel

En dan zit het bijwerken van de $actions array verstopt in de checkYesNo-functie, waarmee die functie ook gekoppeld is aan deze vragen/acties en niet voor willekeurige andere yes/no-vragen gebruikt kan worden.

Nog even terug naar die *Question-functies die alleen maar yesno() aanroepen met elk hun eigen vraag. Je zou die kunnen vervangen door een associatieve array (stap 2 nu weggelaten; blijft gelijk):
Bash:
1
2
3
4
5
6
7
8
9
10
11
declare -A action_questions=(
    [foo]="Install app?"
    [bar]="Perform action X?"
)
actions_to_run=()

for action in ${!action_questions[@]}; do
    if yesno ${action_questions[$action]}; then
        actions_to_run+=($action)
    fi
done

Maar dan heb je geen controle meer over de volgorde waarin de vragen gesteld worden. Met een gewone array kun je de actienaam en vraag ook aan elkaar plakken en dan steeds alleen het deel pakken dat je nodig hebt (dit is uit te breiden tot meer dan twee componenten):
Bash:
1
2
3
4
5
6
7
8
9
10
11
action_questions=(
    "foo:Install app?"
    "bar:Perform action X?"
)
actions_to_run=()

for action in "${action_questions[@]}"; do
    if yesno ${action%*:}; then
        actions_to_run+=(${action##:*})
    fi
done

Ietsje minder "clean" dan met associatieve array, maar de volgorde ligt vast in de array en het werkt (waarschijnlijk) ook met versies van bash die geen associatieve arrays hebben (versie 4 uit 2009).

Je kunt ook gewoon de *Question-functies behouden (of variabelen definiëren als fooQuestion="Install app?"). Ze zijn best kort en dan kun je (mocht dat nodig zijn) voor een bepaalde actie toch makkelijk iets anders doen. Bovendien kun je dan ervoor kiezen om bijbehorende vraag- en actiefunctie bij elkaar te houden ipv alle vragen achter elkaar in een lijst bij elkaar zoals in bovenstaande voorbeelden.

En nu is het genoeg ;)

[ Voor 7% gewijzigd door Raynman op 24-09-2015 23:55 ]


Acties:
  • 0 Henk 'm!

  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Ik denk dat ik hem snap. Ik heb alleen nog een vraagje over
code:
1
if ${action}_question;

en
code:
1
 if yesno ${action%*:};

Ik voel mee een beetje dom :$ Maar ik kon het niet met Google vinden. Is dit een test met als resultaat true/false of 1/0?

[ Voor 3% gewijzigd door JT op 25-09-2015 23:24 ]

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning


  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 14:15
Oeps, die eerste moest uiteraard
Bash:
1
if ${action}Question;
zijn om jouw naamgeving aan te houden. Daarbij is ${action} dus achtereenvolgens "foo" en "bar" -- de bijbehorende functies die dan aangeroepen worden (fooQuestion/barQuestion) stonden erbij -- en yesno() had je al gezien en begrepen. Over de if hebben we het eerder al gehad (en "bash if" googelen werkt ook prima), dus misschien begrijp ik je vraag niet helemaal, maar anders zou ik "ja" zeggen.

Acties:
  • 0 Henk 'm!

  • JT
  • Registratie: November 2000
  • Laatst online: 09-10 16:05

JT

VETAK y0

Topicstarter
Bash if werkt prima in de zin van dat je voorbeelden tegenkomt met argumenten. Bijvoorbeeld -Z <filename> ofzo. Maar ik zie dat hier een test gebeurt zonder argument. Daarover heb ik echt niet gevonden wat dat doet. Normaal zeg je "als <variabele> <conditie>" waarbij je operators of argumenten gebruikt. Ik weet niet wat er gebeurt als je dus alleen "if" met een variabele gebruikt. Dat heb ik niet kunnen vinden met zoektermen als "bash test if shorthand" of "bash test without argument".

3600wp string @ 115° oost | 825wp panelen/750wp micro's @ 13°/115° oost | 1475wp panelen / 1250wp micro's @ 27°/205° graden zuid
Ecodan warmtepomp
Repo's: HA-Solar-control | HA-heatpump-planning

Pagina: 1