Grunden för Bash Scripting

Shell-skript används ofta i UNIX-världen. De är utmärkta för att påskynda repetitiva uppgifter och förenkla komplicerad exekveringslogik. De kan vara lika enkla som en uppsättning kommandon, eller de kan orkestrera komplexa uppgifter. I den här handledningen lär vi oss mer om Bashs skriptspråk genom att skriva ett exempelskript steg för steg.


Fizz-Buzz Problemet

Ett av de bästa sätten att lära sig ett nytt språk är genom exempel. Låt oss börja med en.

Problemet med Fizz-Buzz är en mycket enkel. Det blev känt efter en programmerare, benämnd Imran, använde den som ett intervjuprov. Det visar sig att 90-99,5% av kandidaterna för ett programmeringsjobb helt enkelt inte kan skriva det enklaste programmet. Imran tog detta enkla Fizz-Buzz-spel och bad kandidaterna att lösa det. Många följde Imras exempel, och idag är det en av de mest frågade vanliga frågorna för ett programmeringsjobb. Om du anställer, och behöver ett sätt att filtrera genom 90% av kandidaterna, är detta ett utmärkt problem att presentera.

Här är reglerna:

  • Ta och skriv siffrorna mellan 1 och 100.
  • När ett tal är delbart med 3, skriv ut "Fizz" istället för numret.
  • När det är delbart med 5, skriv ut "Buzz" istället.
  • När det är delbart både med 3 och 5, skriv ut "FizzBuzz".

Det är allt som finns där. Jag är säker på att de flesta av er redan kan visualisera de två eller tre om uttalanden för att lösa detta. Låt oss arbeta igenom det här med hjälp av Bashs skriptspråk.


shebang

A shebang refererar till kombinationen av hash och utropstecken tecken: #!. Programläsaren söker efter en shebang på första raden i manuset och använder tolken som anges i den. En shebang består av följande syntax: #!tolk [parametrar]. Tolken är det program som används för att tolka vårt språk. För bash scripting, det skulle vara / Bin / bash. Om du till exempel vill skapa ett skript i PHP och köra det i konsolen, skulle du förmodligen vilja använda den / Usr / bin / php (eller sökvägen till PHP körbar på din maskin) som tolk.

#! / Usr / bin / php  

Ja, det kommer faktiskt att fungera! Är det inte enkelt? Var noga med att göra din fil körbar först. När du har gjort, kommer det här skriptet att mata ut din PHP-information som du förväntar dig.

Tips: För att säkerställa att ditt skript kommer att fungera på så många system som möjligt kan du använda / Bin / env i shebang. Som sådan, istället för / Bin / bash, du kan använda / bin / env bash, som kommer att fungera på system där bash exekverbar inte finns inom / bin.


Utmatning av text

Utskriften av ett skript kommer att vara lika med, som du kan förvänta dig, vad som helst som utmatas från ditt kommando. Men om vi uttryckligen vill skriva något till skärmen kan vi använda det eko.

#! / bin / bash echo "Hello World"

När du kör detta skript kommer du att skriva ut "Hello World" i konsolen.

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

Introducerar variabler

Som med alla programmeringsspråk kan du använda variabler när du skriver skalskript.

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

Denna kod producerar exakt samma "Hello World" -meddelande. Som du kan se, för att tilldela ett värde till en variabel, skriv bara namnet - uteslut dollarn tecknet framför det. Var också försiktig med utrymmen; Det kan inte finnas några mellanslag mellan variabelnamnet och likartat tecken. Så message = "Hello" istället för message = 'Hej'

När du vill använda en variabel kan du ta värdet av det precis som vi gjorde i eko kommando. Förbereder en $ till variabelns namn returnerar dess värde.

Tips: Semikolon krävs inte i bash scripting. Du kan använda dem i de flesta fall, men var försiktig: de kan ha en annan betydelse än vad du förväntar dig.


Skriva ut siffrorna mellan 1 och 100

Fortsatt med vårt demoprojekt måste vi cykla igenom alla tal mellan 1 och 100. För detta behöver vi använda en för slinga.

#! / bin / bash för nummer i 1 ... 100; gör echo $ nummer gjort

Det finns flera nya saker som är värda att notera i detta exempel - som förresten skriver ut alla siffror från 1 till 100, ett tal i taget.

  • De för syntaxen i bash är: för VARIABLE i RANGE; gör COMMAND gjort.
  • De lockiga axlarna kommer att transformeras 1 ... 100 till ett område i vårt exempel. De används också i andra sammanhang, som vi kommer att granska inom kort.
  • do och för är faktiskt två separata kommandon. Om du vill placera två kommandon på en enda rad måste du separera dem på något sätt. Ett sätt är att använda semikolon. Alternativt kan du skriva koden utan en semikolon genom att flytta do till följande rad.
#! / bin / bash för nummer i 1 ... 100 gör echo $ nummer gjort

Det första beslutet

Nu när vi vet hur man skriver ut alla siffror mellan 1 och 100 är det dags att göra vårt första beslut.

#! / bin / bash för nummer i 1 ... 100; gör om [$ ((antal% 3)) -eq 0]; sedan echo "Fizz" annars echo $ nummer fi gjort

Detta exempel kommer att mata ut "Fizz" för nummer delbart med 3. Återigen måste vi hantera lite ny syntax. Låt oss ta dem en efter en.

  • om ... då ... annars ... fi - Det här är den klassiska syntaxen för en om uttalande i Bash. Självklart är det annan del är valfri - men krävs för vår logik i det här fallet.
  • om COMMAND-RETURN-VALUE; sedan… - om kommer att utföras om kommandot avkastningsvärde är noll. Ja, logiken i Bash är nollbaserad, vilket betyder att kommandon som körs exekveras avslutas med en kod på 0. Om något går fel kommer å andra sidan ett positivt heltal att returneras. För att förenkla saker: allt annat än 0 beaktas falsk.
  • Matematiska uttryck i Bash anges av dubbla parenteser. $ ((Nummer% 3)) kommer att returnera det återstående värdet av att dividera variabeln, siffra, med 3. Observera att vi inte använde $ inuti parentesen - bara framför dem.

Du kanske undrar var kommandot är i vårt exempel. Finns det inte bara en konsol med ett udda uttryck i det? Tja, det visar sig det [ är faktiskt ett körbart kommando. För att leka med det här, prova följande kommandon i konsolen.

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

Tips: Ett kommandos exitvärde returneras alltid till variabeln, ? (frågetecken). Det skrivs över efter varje nytt kommandos körning.


Söker efter Buzz

Vi har det bra så långt. Vi har "Fizz"; nu ska vi göra "Buzz" -delen.

#! / bin / bash för nummer i 1 ... 100; gör om [$ ((antal% 3)) -eq 0]; Echo sedan "Fizz" elif [$ ((antal% 5)) -eq 0]; sedan echo "Buzz" annars echo $ nummer fi gjort

Ovan har vi infört ett annat villkor för delbarhet med 5: a elif påstående. Detta översätter naturligtvis till annars om, och kommer att utföras om kommandot som följer det returnerar Sann (eller 0). Som du kan observera, de villkorliga uttalandena inom [] utvärderas vanligtvis med hjälp av parametrar, t.ex. -eq, som står för "jämställdhet".

För syntaxen, arg1 OP arg2, OP är en av -eq, -ne, -lt, -le, -gt, eller -gE. Dessa aritmetiska binäroperatörer återvänder Sann om arg1 är lika med, inte lika med, mindre än, mindre än eller lika med, större än eller större än eller lika med arg2, respektive.arg1 och arg2 kan vara positiva eller negativa heltal. - Bash Manual

När du försöker jämföra strängar kan du använda den välkända == tecken, eller ens ett enda lika tecken kommer att göra. != avkastning Sann när strängarna är olika.


Men koden är inte helt korrekt

Hittills kör koden, men logiken är inte korrekt. När numret är delbart med både 3 och 5, kommer vår logik bara att echo "Fizz". Låt oss ändra vår kod för att uppfylla det sista kravet på FizzBuzz.

#! / bin / bash för nummer i 1 ... 100; gör om [$ ((antal% 3)) -eq 0]; sedan output = "Fizz" fi om [$ ((antal% 5)) -eq 0]; sedan output = "$ output Buzz" fi om [-z $ output]; sedan echo $ number else echo $ output; fi gjort

Återigen måste vi göra en handfull förändringar. Den mest anmärkningsvärda är införandet av en variabel, och sedan sammanbindningen av "Buzz" till den, om så är nödvändigt. Strängar i bash definieras typiskt mellan dubbla citat ("). Enstaka citat kan också användas, men för enklare sammanfogning är dubblar det bättre valet. Inom dessa dubbla citat kan du referera till variabler: lite text $ variabel någon annan text" kommer ersätta $ variabel med dess innehåll. När du vill sammanfoga variabler med strängar utan mellanslag mellan dem, kanske du föredrar att placera variabelns namn i lockiga axlar. I de flesta fall, som PHP, behöver du inte göra det, men det hjälper mycket när det gäller kodens läsbarhet.

Tips: Du kan inte jämföra tomma strängar. Det skulle återställa en saknad parameter.

På grund av argument inom [] behandlas som parametrar för "[", De måste skilja sig från en tom sträng. Så det här uttrycket, även om det är logiskt, kommer att ge ett fel: [$ output! = ""]. Det är därför vi har använt [-z $ utgång], som återvänder Sann om strängen har en längd av noll.


Extrahera metod för logisk uttryck

Ett sätt att förbättra vårt exempel är att extrahera i funktioner det matematiska uttrycket från om uttalanden, som så:

#! / bin / bash-funktionen ärDivisibleBy return $ (($ 1% $ 2)) för nummer i 1 ... 100; gör om isDivisibleBy $ nummer 3; sedan output = "Fizz" fi om isDivisibleBy $ number 5; sedan output = "$ output Buzz" fi om [-z $ output]; sedan echo $ number else echo $ output; fi gjort

Vi tog uttryck som jämför resten med noll och flyttade dem till en funktion. Ännu mer eliminerade vi jämförelsen med noll, eftersom noll betyder sant för oss. Vi behöver bara returnera värdet från det matematiska uttrycket - väldigt enkelt!

Tips: En funktions definition måste föregås av samtalet.

I Bash kan du definiera en metod som funktion func_name kommandon; . Eventuellt finns det en andra syntax för att deklarera funktioner: func_name () kommandon; . Så vi kan släppa strängen, fungera och lägg till "()" efter dess namn Personligen föredrar jag det här alternativet, som exemplifierat i exemplet ovan. Det är mer explicit och liknar traditionella programmeringsspråk.

Du behöver inte ange parametrarna för en funktion i Bash. Att skicka parametrar till en funktion uppnås genom att helt enkelt räkna över dem efter att funktionssamtalet är åtskilt med vita mellanslag. Placera inte kommatecken eller parentes i funktionssamtalet - det fungerar inte.

Mottagna parametrar tilldelas automatiskt till variabler enligt nummer. Den första parametern går till $ 1, den andra till $ 2, och så vidare. Den speciella variabeln, $ 0 refererar till det aktuella skriptets filnamn.

Låt oss spela med parametrar

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

Denna kod kommer att producera följande utdata:

csaba @ csaba ~ $ ./parametersExamples.sh one ./parametersExamples.sh en två tre enXtwoXthre

Låt oss analysera källan, rad för rad.

  • Den sista raden är funktionssamtalet. Vi kallar det med tre strängparametrar.
  • Den första raden efter shebang är funktionsdefinitionen.
  • Den första raden i funktionen matar ut den första parametern: "en". Hittills så enkelt.
  • Den andra raden matar ut nuvarande skriptets filnamn. Återigen, väldigt enkelt.
  • Den tredje raden ändrar standard teckenavskiljaren till bokstaven, "X". Som standard är detta "" (ett mellanslag). Så vet Bash hur parametrarna är separerade.
  • Den fjärde raden matar ut en särskild variabel, $ @. Den representerar alla parametrar som ett enda ord, precis som det anges i funktionssamtalet.
  • Slutlinjen matar ut en annan speciell variabel, $ *. Den representerar alla parametrar, taget en-för-en och sammanfogad med första bokstaven i IFS-variabeln. Det är därför resultatet är oneXtwoXthre.

Retursträngar från funktioner

Som jag påpekade tidigare kan funktioner i Bash bara returnera heltal. Som sådan skriver returnera "en sträng" skulle vara ogiltig kod. Fortfarande, i många situationer behöver du mer än bara en noll eller en. Vi kan refactor vårt FizzBuzz exempel så att, i för uttalande, vi kommer bara att ringa ett funktionssamtal.

#! / bin / bash funktionen ärDivisibleBy return $ (($ 1% $ 2)) funktion fizzOrBuzz if isDivisibleBy $ 1 3; sedan output = "Fizz" fi om isDivisibleBy $ 1 5; sedan output = "$ output Buzz" fi om [-z $ output]; sedan echo $ 1 else echo $ output; fi för nummer i 1 ... 100; gör fizzOrBuzz $ nummer gjort

Tja, det här är det första steget. Vi har bara extraherat hela koden till en funktion, kallad fizzOrBuzz, och sedan ersättas $ nummer med $ 1. Men all utmatning sker i fizzOrBuzz fungera. Vi vill producera från för loop med en eko uttalande, så att vi kan förordna varje rad med en annan sträng. Vi måste fånga fizzOrBuzz funktionens utgång.

# [...] för nummer i 1 ... 100; gör echo "-'fizzOrBuzz $ nummer '" fizzBuzzer = $ (fizzOrBuzz $ nummer) echo "- $ fizzBuzzer" gjort

Vi har uppdaterat vår för loop bara lite (inga andra ändringar). Vi har nu echoed allt två gånger på två olika sätt för att exemplifiera skillnaderna mellan de två lösningarna på samma problem.

Den första lösningen för att fånga utmatningen från en funktion eller ett annat kommando är att använda backticks. I 99% av fallen kommer det att fungera bra. Du kan helt enkelt referera till en variabel inom backticks av deras namn, som vi gjorde med $ nummer. De första linjerna i produktionen ska nu se ut som:

csaba @ csaba ~ / Personal / Programming / NetTuts / Grunderna i BASH Scripting / Källor $ ./fizzBuzz.sh -1 -1 -2 -2 -Fizz -Fizz -4 -4 -Buzz -Buzz -Fizz -Fizz -7 -7

Som du kan se är allt duplicerat. Samma utmatning.

För den andra lösningen har vi valt att först tilldela returvärdet till en variabel. I den uppgiften använde vi ($), som i detta fall forxlar skriptet, exekverar koden och returnerar dess utmatning.


;, && och ||

Kommer du ihåg att vi använde semikolon här och där? De kan användas för att utföra flera kommandon skrivna på samma rad. Om du separerar dem med semikolon kommer de helt enkelt att bli exekverade.

Ett mer sofistikerat fall är att använda && mellan två kommandon. Ja, det är en logisk AND; det betyder att det andra kommandot kommer att utföras endast om den första återkommer Sann (det går ut med 0). Detta är till hjälp vi kan förenkla om uttalanden i dessa stenografi:

Funktionen fizzOrBuzz isDivisibleBy $ 1 3 && output = "Fizz" ärDivisibleBy $ 1 5 && output = "$ output Buzz" om [-z $ output ]; sedan echo $ 1 else echo $ output; fi för nummer i 1 ... 100; gör echo "-'fizzOrBuzz $ nummer" "gjort

Som vår funktion, isDivisibleBy returnerar ett korrekt returvärde, vi kan sedan använda && för att ställa in den variabel vi vill ha. Vad är efter && kommer endast att utföras om villkoret är Sann. På samma sätt kan vi använda || (dubbelrörtecken) som en logisk OR. Här är ett snabbt exempel nedan.

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

Slutgiltiga tankar

Så det gör det för den här handledningen! Jag hoppas att du har plockat upp en handfull nya tips och tekniker för att skriva egna Bash-skript. Tack för att du läste och håll dig uppdaterad för mer avancerade artiklar om detta ämne.