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.
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:
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.
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 / phpJa, 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 $ berichtDeze 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 vanmessage = '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 klaarEr zijn verschillende nieuwe dingen die het vermelden waard zijn in dit voorbeeld - dat trouwens alle getallen van 1 tot 100, één cijfer tegelijk afdrukt.
voor
syntaxis in Bash is: voor VARIABLE in RANGE; do COMMAND gedaan
.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
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
.$ ((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.
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 terugwaar
alsarg1
is gelijk aan, niet gelijk aan, kleiner dan, kleiner dan of gelijk aan, groter dan of groter dan of gelijk aanarg2
, respectievelijk.arg1
enarg2
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.
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.
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.
#! / 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.
$ @
. Het vertegenwoordigt alle parameters als een enkel woord, precies zoals gespecificeerd in de functieaanroep.$ *
. 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
.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.
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 ~ $
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.