De grondbeginselen van Bash-scripts

Shell-scripts worden veel gebruikt in de UNIX-wereld. Ze zijn uitstekend voor het versnellen van repetitieve taken en het vereenvoudigen van complexe uitvoeringslogica. Ze kunnen zo eenvoudig zijn als een reeks opdrachten, of ze kunnen complexe taken orkestreren. In deze zelfstudie leren we meer over de Bash-scripttaal door stapsgewijs een voorbeeldscript te schrijven.


Het Fizz-Buzz-probleem

Een van de beste manieren om een ​​nieuwe taal te leren, is bijvoorbeeld. Laten we beginnen met een.

Het Fizz-Buzz-probleem is heel eenvoudig. Het werd beroemd na een programmeur, genaamd Imran, gebruikte het als een interviewtest. Het blijkt dat 90-99,5% van de kandidaten voor een programmeeropdracht eenvoudigweg niet in staat zijn om het eenvoudigste programma te schrijven. Imran nam dit eenvoudige Fizz-Buzz-spel en vroeg de kandidaten om het op te lossen. Velen volgden het voorbeeld van Imran en het is vandaag een van de meest gestelde veelgestelde vragen voor een programmeeropdracht. Als u personeel inhuurt en een manier nodig hebt om 90% van de kandidaten te filteren, is dit een groot probleem om te presenteren.

Dit zijn de regels:

  • Neem de getallen tussen 1 en 100 en druk ze af.
  • Wanneer een nummer deelbaar is door 3, drukt u op "Fizz" in plaats van op het nummer.
  • Wanneer het deelbaar is door 5, drukt u in plaats daarvan "Buzz" af.
  • Wanneer het deelbaar is door zowel 3 als 5, druk je "FizzBuzz" af.

Dat is alles wat er is. Ik weet zeker dat de meesten van jullie de twee of drie al kunnen visualiseren als verklaringen om dit op te lossen. Laten we dit doornemen met behulp van de Bash-scripttaal.


Keet

Een shebang verwijst naar de combinatie van de hash- en uitroeptekens: #!. De programma-lader zoekt naar een script op de eerste regel van het script en gebruikt de interpreter die daarin is opgegeven. Een shebang bestaat uit de volgende syntaxis: #!tolk [parameters]. De tolk is het programma dat wordt gebruikt om onze taal te interpreteren. Voor bash-scripting zou dat zijn / Bin / bash. Als u bijvoorbeeld een script in PHP wilt maken en het in console wilt uitvoeren, wilt u het waarschijnlijk gebruiken / Usr / bin / php (of het pad naar de PHP uitvoerbaar op uw machine) als de tolk.

#! / Usr / bin / php  

Ja, dat zal echt werken! Is het niet simpel? Zorg er wel voor dat u eerst uw bestand uitvoerbaar maakt. Zodra u dit doet, zal dit script uw ​​PHP-informatie uitvoeren zoals u zou verwachten.

Tip: Om ervoor te zorgen dat uw script op zoveel mogelijk systemen werkt, kunt u gebruiken / Bin / env in de shebang. Als zodanig in plaats van / Bin / bash, je zou kunnen gebruiken / bin / env bash, die zal werken op systemen waar het bash-bestand niet in zit / bin.


Tekst uitvoeren

De uitvoer van een script zal gelijk zijn aan, zoals je zou verwachten, wat er uit je commando wordt uitgevoerd. Als we echter expliciet iets willen schrijven op het scherm, kunnen we dit gebruiken echo.

#! / bin / bash echo "Hallo wereld"

Als dit script wordt uitgevoerd, wordt 'Hallo wereld' in de console afgedrukt.

csaba @ csaba ~ $ ./helloWorld.sh Hello World csaba @ csaba ~ $

Introductie van variabelen

Zoals met elke programmeertaal, kunt u bij het schrijven van shellscripts variabelen gebruiken.

#! / bin / bash message = "Hello World" echo $ bericht

Deze code produceert precies hetzelfde "Hello World" -bericht. Zoals je kunt zien, om een ​​waarde aan een variabele toe te kennen, hoef je alleen maar de naam ervan te noteren - sluit het dollarteken er voor uit. Wees ook voorzichtig met spaties; er kunnen geen spaties zijn tussen de naam van de variabele en het gelijkteken. Zo message = "Hello" in plaats van message = 'Hallo'

Wanneer u een variabele wilt gebruiken, kunt u de waarde ervan gebruiken, net als in de echo commando. Voorbereiden van een $ om de naam van de variabele de waarde terug te geven.

Tip: Puntkomma's zijn niet vereist bij bash-scripting. Je kunt ze in de meeste gevallen gebruiken, maar wees voorzichtig: ze kunnen een andere betekenis hebben dan je verwacht.


De nummers afdrukken tussen 1 en 100

We gaan door met ons demoproject en moeten alle getallen tussen 1 en 100 doorlopen. Hiervoor moeten we een voor lus.

#! / bin / bash voor nummer in 1 ... 100; doe echo $ nummer klaar

Er zijn verschillende nieuwe dingen die het vermelden waard zijn in dit voorbeeld - dat trouwens alle getallen van 1 tot 100, één cijfer tegelijk afdrukt.

  • De voor syntaxis in Bash is: voor VARIABLE in RANGE; do COMMAND gedaan.
  • De accolades zullen transformeren 1 ... 100 in een bereik in ons voorbeeld. Ze worden ook in andere contexten gebruikt, die we binnenkort zullen bespreken.
  • do en voor zijn eigenlijk twee afzonderlijke opdrachten. Als u twee opdrachten op één regel wilt plaatsen, moet u ze op de een of andere manier scheiden. Een manier is om puntkomma te gebruiken. Als alternatief kunt u de code zonder een puntkomma schrijven door te verplaatsen do naar de volgende regel.
#! / bin / bash voor nummer in 1 ... 100 echo $ nummer gereed

De eerste beslissing

Nu we weten hoe we alle getallen tussen 1 en 100 moeten afdrukken, is het tijd om onze eerste beslissing te nemen.

#! / bin / bash voor nummer in 1 ... 100; doe als [$ ((aantal% 3)) -eq 0]; dan echo "Fizz" anders echo $ nummer fi gedaan

In dit voorbeeld wordt "Fizz" weergegeven voor getallen die deelbaar zijn door 3. Opnieuw hebben we te maken met een beetje nieuwe syntaxis. Laten we ze een voor een nemen.

  • als ... dan ... anders ... fi - dit is de klassieke syntaxis voor een als verklaring in Bash. Natuurlijk, de anders deel is optioneel - maar vereist in dit geval onze logica.
  • als COMMAND-RETOUR-WAARDE; dan… - als wordt uitgevoerd als de retourwaarde van het commando nul is. Ja, de logica in Bash is gebaseerd op nul, wat betekent dat opdrachten die worden uitgevoerd, met een code van 0 worden afgesloten. Als er iets fout gaat, wordt een positief geheel getal geretourneerd. Om dingen te vereenvoudigen: alles behalve 0 wordt overwogen vals.
  • Wiskundige uitdrukkingen in Bash worden gespecificeerd door dubbele haakjes. $ ((Nummer% 3)) retourneert de resterende waarde van het delen van de variabele, aantal, door 3. Houd er rekening mee dat we niet hebben gebruikt $ tussen de haakjes - alleen voor hen.

Je vraagt ​​je misschien af ​​waar het commando in ons voorbeeld staat. Is er niet alleen een haakje met een vreemde uitdrukking erin? Nou ja, dat blijkt [ is eigenlijk een uitvoerbaar commando. Om hier mee te spelen, probeer je de volgende commando's in je console.

csaba @ csaba ~ $ welke [/ usr / bin / [csaba @ csaba ~ $ [0 -eq 1] csaba @ csaba ~ $ echo $? 1 csaba @ csaba ~ $ [0 -eq 0] csaba @ csaba ~ $ echo $? 0

Tip: De exitwaarde van een opdracht wordt altijd teruggegeven aan de variabele, ? (vraagteken). Het wordt overschreven na de uitvoering van elke nieuwe opdracht.


Zoeken naar Buzz

Het gaat tot nu toe goed met ons. We hebben "Fizz"; laten we nu het deel "Buzz" doen.

#! / bin / bash voor nummer in 1 ... 100; doe als [$ ((aantal% 3)) -eq 0]; dan echo "Fizz" elif [$ (getal% 5)) -eq 0]; dan echo "Buzz" anders echo $ nummer fi gedaan

Hierboven hebben we een andere voorwaarde voor deelbaarheid geïntroduceerd met 5: de elif uitspraak. Dit vertaalt zich natuurlijk naar anders als, en wordt uitgevoerd als de volgende opdracht volgt waar (of 0). Zoals je kunt zien, zijn de voorwaardelijke uitspraken binnenin [] worden meestal geëvalueerd met behulp van parameters, zoals -eq, wat staat voor "gelijken".

Voor de syntaxis, arg1 OP arg2, OP is een van -eq, -ne, -lt, -le, -gt, of -ge. Deze rekenkundige binaire operatoren keren terug waar als arg1 is gelijk aan, niet gelijk aan, kleiner dan, kleiner dan of gelijk aan, groter dan of groter dan of gelijk aan arg2, respectievelijk.arg1 en arg2 kunnen positieve of negatieve gehele getallen zijn. - Bash Manual

Wanneer u strings probeert te vergelijken, kunt u het bekende gebruiken == teken, of zelfs een enkel gelijkteken. != komt terug waar wanneer de snaren anders zijn.


Maar de code is niet helemaal juist

Tot nu toe loopt de code, maar de logica is niet correct. Wanneer het getal deelbaar is door zowel 3 als 5, zal onze logica alleen 'Fizz' herhalen. Laten we onze code aanpassen om te voldoen aan de laatste vereiste van FizzBuzz.

#! / bin / bash voor nummer in 1 ... 100; doe als [$ ((aantal% 3)) -eq 0]; dan output = "Fizz" fi als [$ ((nummer% 5)) -eq 0]; output = "$ output Buzz" fi if [-z $ output]; vervolgens echo $ -nummer anders echo $ -uitvoer; ik ben klaar

Nogmaals, we hebben een handvol wijzigingen aangebracht. De meest opvallende is de introductie van een variabele en vervolgens de aaneenschakeling van "Buzz", indien nodig. Strings in bash worden meestal gedefinieerd tussen dubbele aanhalingstekens ("). Enkele aanhalingstekens kunnen ook worden gebruikt, maar voor eenvoudiger aaneenschakeling zijn doubles de betere keuze.U kunt binnen deze dubbele aanhalingstekens verwijzen naar variabelen: wat tekst $ variabele een andere tekst" zal vervangen $ variable met zijn inhoud. Wanneer u variabelen met tekenreeksen wilt samenvoegen zonder spaties ertussen, geeft u er misschien de voorkeur aan de naam van de variabele tussen accolades te plaatsen. In de meeste gevallen, zoals PHP, hoef je dit niet te doen, maar het helpt veel als het gaat om de leesbaarheid van de code.

Tip: Je kunt lege strings niet vergelijken. Dat zou een ontbrekende parameter retourneren.

Omdat argumenten binnen [] worden behandeld als parameters, voor "[", ze moeten anders zijn dan een lege string. Dus deze uitdrukking, hoewel logisch, geeft een foutmelding: [$ output! = ""]. Dat is waarom we hebben gebruikt [-z $ uitvoer], welke terugkeert waar als de string een lengte van nul heeft.


Extractiemethode voor logische expressie

Een manier om ons voorbeeld te verbeteren is om de wiskundige uitdrukking uit het als verklaringen, zoals zo:

#! / bin / bash-functie isDivisibleBy return $ (($ 1% $ 2)) voor nummer in 1 ... 100; doe of isDivisibleDoor $ nummer 3; dan output = "Fizz" fi if isDivisibleBy $ nummer 5; output = "$ output Buzz" fi if [-z $ output]; vervolgens echo $ -nummer anders echo $ -uitvoer; ik ben klaar

We hebben de uitdrukkingen gebruikt om de rest te vergelijken met nul, en hebben ze naar een functie verplaatst. Sterker nog, we hebben de vergelijking met nul geëlimineerd, want nul betekent voor ons waar. We hoeven alleen de waarde van de wiskundige uitdrukking terug te geven - heel eenvoudig!

Tip: De functie van een functie moet aan zijn oproep voorafgaan.

In Bash kun je een methode als definiëren function func_name commands; . Optioneel is er een tweede syntaxis voor het declareren van functies: func_name () commands; . Dus we kunnen de reeks laten vallen, functie en voeg toe "()" naar de naam. Ik geef persoonlijk de voorkeur aan deze optie, zoals in het bovenstaande voorbeeld wordt geïllustreerd. Het is meer expliciet en lijkt op traditionele programmeertalen.

U hoeft de parameters voor een functie in Bash niet op te geven. Het verzenden van parameters naar een functie wordt bereikt door eenvoudigweg erover te noemen nadat de functieaanroep gescheiden is door witte spaties. Plaats geen komma's of haakjes in de functieaanroep - het zal niet werken.

Ontvangen parameters worden automatisch toegewezen aan variabelen op nummer. De eerste parameter gaat naar $ 1, de tweede om $ 2, enzovoorts. De speciale variabele, $ 0 verwijst de bestandsnaam van het huidige script.

Laten we spelen met parameters

#! / bin / bash-functie exampleFunc echo $ 1 echo $ 0 IFS = "X" echo "$ @" echo "$ *" exampleFunc "one" "two" "three"

Deze code produceert de volgende uitvoer:

csaba @ csaba ~ $ ./parametersExamples.sh one ./parametersExamples.sh one two thre oneXtwoXthre

Laten we de bron regel voor regel analyseren.

  • De laatste regel is de functieaanroep. We noemen dit met drie stringparameters.
  • De eerste regel na de shebang is de functiedefinitie.
  • De eerste regel in de functie voert de eerste parameter uit: "één". Tot dusver zo eenvoudig.
  • De tweede regel voert de bestandsnaam van het huidige script uit. Nogmaals, heel eenvoudig.
  • De derde regel verandert het standaardtekenscheider in de letter "X". Standaard is dit "" (een spatie). Dat is hoe Bash weet hoe de parameters zijn gescheiden.
  • De vierde regel voert een speciale variabele uit, $ @. Het vertegenwoordigt alle parameters als een enkel woord, precies zoals gespecificeerd in de functieaanroep.
  • De laatste regel voert nog een speciale variabele uit, $ *. Het geeft alle parameters weer, één voor één genomen en samengevoegd met de eerste letter van de IFS-variabele. Dat is waarom het resultaat is oneXtwoXthre.

Terugkerende strings van functies

Zoals ik eerder heb opgemerkt, kunnen functies in Bash alleen gehele getallen retourneren. Als zodanig, schrijven return "a string" zou een ongeldige code zijn. Toch heb je in veel situaties meer nodig dan alleen een nul of één. We kunnen ons FizzBuzz-voorbeeld refactoren zodat in de voor verklaring, we zullen gewoon een functieaanroep doen.

#! / bin / bash-functie isDivisibleBy return $ (($ 1% $ 2)) function fizzOrBuzz if isDivisibleBy $ 1 3; dan output = "Fizz" fi if isDivisibleBy $ 1 5; output = "$ output Buzz" fi if [-z $ output]; dan echo $ 1 anders echo $ output; fi voor nummer in 1 ... 100; doe fizzOrBuzz $ nummer klaar

Welnu, dit is de eerste stap. We hebben zojuist alle code geëxtraheerd in een functie, genaamd fizzOrBuzz, en dan vervangen $ number met $ 1. Alle uitvoer vindt echter plaats in de fizzOrBuzz functie. We willen output van de voor loop met een echo verklaring, zodat we elke regel kunnen vervangen door een andere reeks. We moeten de fizzOrBuzz functie uitvoer.

# [...] voor nummer in 1 ... 100; do echo "-'fizzOrBuzz $ number '" fizzBuzzer = $ (fizzOrBuzz $ number) echo "- $ fizzBuzzer" klaar

We hebben onze voor loop gewoon een beetje (geen andere wijzigingen). We hebben nu alles op twee verschillende manieren herhaald om de verschillen tussen de twee oplossingen voor hetzelfde probleem te illustreren.

De eerste oplossing om de uitvoer van een functie of een andere opdracht vast te leggen, is om backticks te gebruiken. In 99% van de gevallen werkt dit prima. Je kunt simpelweg verwijzen naar een variabele binnen backticks op hun naam, zoals we deden met $ number. De eerste paar regels van de uitvoer moeten er nu als volgt uitzien:

csaba @ csaba ~ / Persoonlijk / Programmeren / NetTuts / De grondbeginselen van BASH Scripting / Bronnen $ ./fizzBuzz.sh -1 -1 -2 -2 -Fizz -Fizz -4 -4 -Buzz -Buzz -Fizz -Fizz -7 -7

Zoals u kunt zien, is alles gedupliceerd. Dezelfde output.

Voor de tweede oplossing hebben we ervoor gekozen om de retourwaarde eerst toe te wijzen aan een variabele. In die opdracht hebben we gebruikt $ (), die in dit geval het script opschrijft, de code uitvoert en de uitvoer retourneert.


;, && en ||

Weet je nog dat we hier en daar een puntkomma gebruikten? Ze kunnen worden gebruikt om verschillende opdrachten uit te voeren die op dezelfde regel zijn geschreven. Als u ze scheidt met puntkomma's, worden ze gewoon gewoon uitgevoerd.

Een meer geavanceerd geval is om te gebruiken && tussen twee opdrachten. Ja, dat is een logische EN; dit betekent dat de tweede opdracht alleen wordt uitgevoerd als de eerste wordt geretourneerd waar (het eindigt met 0). Dit is nuttig; we kunnen het vereenvoudigen als uitspraken in deze korte beschrijving:

#! / bin / bash-functie isDivisibleBy return $ (($ 1% $ 2)) function fizzOrBuzz isDivisibleBy $ 1 3 && output = "Fizz" isDivisibleBy $ 1 5 && output = "$ output Buzz" if [-z $ output ]; dan echo $ 1 anders echo $ output; fi voor nummer in 1 ... 100; do echo "-'fizzOrBuzz $ number '" done

Als onze functie, isDivisibleBy retourneert een goede retourwaarde, dan kunnen we deze gebruiken && om de gewenste variabele in te stellen. Wat is er na && wordt alleen uitgevoerd als de voorwaarde is waar. Op dezelfde manier kunnen we gebruiken || (dubbele pijplijn) als een logische OF. Hier is een kort voorbeeld hieronder.

csaba @ csaba ~ $ echo "bubu" || echo "bibi" bubu csaba @ csaba ~ $ echo false || echo "bibi" false csaba @ csaba ~ $

Laatste gedachten

Dus dat doet het voor deze tutorial! Ik hoop dat je een handvol nieuwe tips en technieken hebt opgedaan voor het schrijven van je eigen Bash-scripts. Bedankt voor het lezen en blijf op de hoogte voor meer geavanceerde artikelen over dit onderwerp.