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.
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:
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.
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 / phpJa, 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 $ meddelandeDenna 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örmessage = '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 gjortDet 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.
för
syntaxen i bash är: för VARIABLE i RANGE; gör COMMAND gjort
.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
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
.$ ((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.
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änderSann
omarg1
är lika med, inte lika med, mindre än, mindre än eller lika med, större än eller större än eller lika medarg2
, respektive.arg1
ocharg2
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.
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.
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.
#! / 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 representerar alla parametrar som ett enda ord, precis som det anges i funktionssamtalet.$ *
. 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
.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.
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 ~ $
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.