Talen en automaten/2011-12/producten/Bash

Uit Werkplaats
Ga naar: navigatie, zoeken

Page Break




Algolfrag.jpg

Talen en automaten

Erik Barendsen


 © comments



Bash

Matjah Sonneveld, Gerco van Heerdt



Talen en automaten 2011-12



13:30 B






Matjah Sonneveld Bachelor Informatica
 e-mail 

cursuspagina

Matjah Sonneveld.jpg

Gerco van Heerdt Bachelor Informatica
 e-mail 

cursuspagina

Gerco van Heerdt.jpg

Page Break





Beschrijving

Bash (Bourne-again shell) werd in 1989 door GNU uitgebracht als vervanging van sh (Bourne shell). Het is de standaard (login) shell op veel besturingssystemen. Het wordt gebruikt om via de commandline de computer te besturen, meestal met simpele commando's die vooral externe programma's aanroepen, maar het is ook mogelijk om er hele programma's (scripts) mee te maken. De taal bevat namelijk dezelfde control-structuren die we in de meeste programmeertalen aantreffen. Wel wijkt de syntax op veel punten nogal af van die van talen die op C lijken. Omdat die soms ook nogal omslachtig is, zijn geavanceerdere scripts moeilijk leesbaar, zeker voor degenen die de taal niet goed kennen. Zulke scripts worden tegenwoordig dan ook vaker in andere talen geschreven.

We hebben voor deze taal gekozen omdat we op er dit moment alleen hele simpele gedeeltes van gebruiken. We willen tijdens het maken van deze casus graag leren welke mooie constructies er allemaal door geaccepteerd worden.

Voorbeelden:

<source lang="bash"> echo Hello World </source>

<source lang="bash"> for countdown in 5 4 3 2 1 do

  echo $countdown

done </source>

Het volgende script loopt over alle bestanden in een map en zijn submappen, telt deze, laat hun naam zien en eventueel waar ze standaard mee uitgevoerd zouden worden als ze uitgevoerd zouden worden en hernoemt ondertussen .htm naar .html bestanden (ik verzin ook maar wat).

<source lang="bash">

  1. !/bin/bash

files=0 directories=(.)

for (( i=0; i < ${#directories[@]}; i=i+1 )) do

   dir=${directories[$i]}/
   echo Entering $dir
   for file in "$dir"*
   do
       if !($file =~ \*$) 
       then
           if [ -d "$file" ]
           then
               directories[${#directories[@]}]=$file
           else
               if $file =~ \.htm$ 
               then
                   echo "$file -> $file"l
                   mv $file $file'l'
               else
                   echo $file`head -n1 "$file" | grep ^#! | sed 's/#!/: /'`
               fi
               files=$(($files + 1))
           fi
       fi
   done

done

unset directories[@]

echo Total files: $files </source>

Merk op dat de eerste regel, die door de taal als commentaar wordt gezien, aangeeft waar de interpreter zich zou moeten bevinden.

Meer informatie is te vinden in de wiki[1] of de man pagina.[2]

Regulier?

Neem aan dat Bash regulier is en zij Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle k} de grenswaarde van het pomplemma. Laat Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle z} de string (die in Bash zit, zie de volgende sectie) (if ((rm -r /) then)Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle ^k} reboot; (fi)Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle ^k} zijn. Om het overzichtelijk te houden definieren we de strings Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle p, q} en Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle r} even als

Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle p} = if (rm -r /) then

Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle q} = reboot;

Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle r} = fi

Dan kunnen we Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle z} schrijven als Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle uvw} , zo dat dat voldoet aan de criteria van het pomplemma. Dan gelden:

Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle u = p^i}

Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle v = p^j}

Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle w = p^{k-i-j} qr^k}

waarbij Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle i + j <= k} en Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle j > 0} . Als we Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle v} pompen krijgen we Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle uv^{l}w} , wat volgens het pomplemma in Bash moet zitten, dus ook

Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle uv^{2}w}  : Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle uv^{2}w = p^i p^{2j} p^{k-i-j}qr^k = p^{k+j}qr^k}

en die zit niet in Bash, omdat er Parsen mislukt (MathML met SVG- of PNG-terugval (aanbevolen voor moderne browsers en toegankelijkheidshulpmiddelen): Ongeldig antwoord ("Math extension cannot connect to Restbase.") van server "https://en.wikipedia.org/api/rest_v1/":): {\displaystyle j} if-statements niet af worden gesloten. Volgens het pomplemma moest deze string wel in Bash zitten, dus was onze aanname incorrect en is Bash geen reguliere taal.

Contextvrij?

Om aan te tonen dat Bash contextvrij is moeten we er een PDA of grammatica voor construeren. We hebben gekozen voor een grammatica. Als bron hiervoor gebruikten we de man pagina van Bash, met name het gedeelte onder Shell Grammar.[3]

Omdat de taal toch behoorlijk uitgebreid bleek te zijn hebben we een aantal dingen overgeslagen. Zo zou WORD ook delen met quotes mogen bevatten ('re'bo"ot" doet bijvoorbeeld hetzelfde als reboot) en hebben we dingen als arrays, comments, MATHEXPRESSION, de niet-alphanumerieke tekens bij PARAMETER, het niet-recursieve gedeelte van EVALEXPRESSION en nog een aantal andere dingetjes overgeslagen. Verder doen we alsof alle mogelijke commando- en bestandsnamen geldig zijn en beschouwen we ingebouwde commando's (bijvoorbeeld time) die als externe commando's geïmplementeerd zouden kunnen worden als externe commando's. Ook gaan we ervan uit dat we de betekenis van SPACE, TAB en NEWLINE niet hoeven te beschrijven. Eigenlijk hebben we geen Bash-specifieke dingen besproken, dus hadden we net zo goed sh kunnen nemen.

Terminals zijn alle combinaties van tekens behalve |, tenzij die direct tegen een (non-)terminal of een andere | aanstaat of er nog geen (non-)terminals gegeven zijn voor de huidige productieregel, die maximaal één hoofdletter bevatten. Om het zo exact mogelijk, maar toch nog een beetje overzichtelijk te houden: een spatie tussen een terminal en een non-terminal of twee terminals betekent dat daar een METALIST staat.

Het startsymbool is PROGRAM.

Main

PROGRAM       → LIST RESTART | FUNCTION RESTART | λ

RESTART       → END PROGRAM

SUBPROGRAM    → LIST END | LIST END SUBPROGRAM

LIST          → SIMPLELIST | COMPOUND | METALIST

SIMPLELIST    → SIMPLE
              | ! META SIMPLE
              | SIMPLE && SIMPLELIST
              | SIMPLE || SIMPLELIST
              | SIMPLE ; SIMPLELIST
              | SIMPLE | SIMPLE
              | SIMPLE REDIRECTION
              | λ

SIMPLE        → VARIABLES META COMMAND META PIPES

COMPOUND      → SUB | GROUP | MATH | EVAL | FORLIST | FORLOOP | SELECT | CASE | IF | WHILE | UNTIL

Simple

VARIABLES     → VARIABLE META VARIABLES | λ

VARIABLE      → VARIABLENAME=OPTIONALWORD

VARIABLENAME  → ALPHA ALPHANUMLIST

COMMAND       → COMMANDNAME META PARAMETERLIST

PARAMETERLIST → PARAMETER PARAMETERLIST | λ

PARAMETER     → ALPHANUM
              | PARAMETER

WORDLIST      → WORD WORDLIST | λ

OPTIONALWORD  → WORD | λ

COMMANDNAME   → PARAMETER

FILENAME      → PARAMETER

WORD          → ALPHANUM ALPHANUMLIST

ALPHA         → a | ... | z
              | A | ... | Z
              | _

ALPHANUMLIST  → ALPHANUM ALPHANUMLIST | λ

ALPHANUM      → ALPHA | NUM

NUMLIST       → NUM NUMLIST | λ

NUM           → 0 | ... | 9

PIPES         → PIPE META PIPES | λ

PIPE          → | | |&

Compound

SUB           → ( SUBPROGRAM )

GROUP         → { META SUBPROGRAM END META }

MATH          → (( MATHEXPRESSION ))

EVAL          → [[ META EVALEXPRESSION META ]]

EVALEXPRESSION → (EVALEXPRESSION)
               | !EVALEXPRESSION
               | EVALEXPRESSION && EVALEXPRESSION
               | EVALEXPRESSION || EVALEXPRESSION

FORLIST       → for META VARIABLENAME META WORDLIST OPTIONALEND do SUBPROGRAM END done

FORLOOP       → for (( MATHEXPRESSION ; MATHEXPRESSION ; MATHEXPRESSION )) DO

SELECT        → select META VARIABLENAME META INWORD DO

DO            → END do META SUBPROGRAM END done

INWORD        → in META WORDLIST | λ

CASE          → case META WORD META in META CASELIST META END esac

CASELIST      → OPTIONALLEFTPARENTHESIS PATTERNLIST SUBPROGRAM CASEENDING | λ

OPTIONALLEFTPARENTHESIS → ( | λ

CASEENDING    → REALCASEENDING CASELIST | λ

REALCASEENDING → ;; | ;& | ;;&

IF            → if SUBPROGRAM END then SUBPROGRAM END ELIFLIST ELSE fi

ELIFLIST      → elif SUBPROGRAM END then SUBPROGRAM END ELIFLIST | λ

ELSE          → else SUBPROGRAM END | λ

WHILE         → while LOOP

UNTIL         → until LOOP

LOOP          → SUBPROGRAM END do SUBPROGRAM END done

Other

FUNCTION      → FUNCTIONDEFNAME COMPOUND REDIRECTION

FUNCTIONDEFNAME → NAME PARENTHESES | function NAME OPTIONALPARENTHESES

OPTIONALPARENTHESES → PARENTHESES | λ

PARENTHESES   → ( )

REDIRECTION   → FILEDESCRIPTOR REDIRECTIONOPERATOR FILEDESCRIPTOR FILENAME REDIRECTION | λ

FILEDESCRIPTOR → NUMLIST

REDIRECTIONOPERATOR → > | < | >& | <& | >&- | <&-

OPTIONALEND   → END | λ

END           → NEWLINE | ;

METALIST      → META METALIST | λ

META          → SPACE | TAB | NEWLINE

Hiermee hebben we aangetoond dat Bash een contextvrije taal is, mits het gedeelte wat we niet hebben beschreven ook contextvrij is, omdat contextvrije talen gesloten zijn onder ∪.