Fundamentals of Bash Scripting

Shell-skript er mye brukt i UNIX-verdenen. De er gode for å øke gjentatte oppgaver og forenkle komplekse utførelseslogikk. De kan være like enkle som et sett med kommandoer, eller de kan orkestrere komplekse oppgaver. I denne opplæringen lærer vi mer om Bashs skriptspråk ved å skrive et eksempelskript trinn for trinn.


Fizz-Buzz Problemet

En av de beste måtene å lære om et nytt språk er ved eksempel. La oss starte med en.

Fizz-Buzz-problemet er en veldig enkel. Det ble kjent etter en programmerer, kalt Imran, brukt den som en intervju test. Det viser seg at 90-99,5% av kandidatene til en programmeringsjobb bare ikke kan skrive det enkleste programmet. Imran tok dette enkle Fizz-Buzz-spillet og ba kandidatene om å løse det. Mange fulgte Imrans eksempel, og i dag er det et av de mest stilte vanlige spørsmålene til en programmeringsjobb. Hvis du ansetter, og trenger en måte å filtrere gjennom 90% av kandidatene, er dette et godt problem å presentere.

Her er reglene:

  • Ta og skriv tallene mellom 1 og 100.
  • Når et tall er delt med 3, skriv ut "Fizz" i stedet for nummeret.
  • Når det er delbart med 5, skriv ut "Buzz" i stedet.
  • Når det er delbart både med 3 og 5, skriv ut "FizzBuzz".

Det er alt der er til det. Jeg er sikker på at de fleste av dere allerede kan visualisere de to eller tre hvis uttalelser for å løse dette. La oss jobbe gjennom dette ved hjelp av Bashs skriptspråk.


shebang

En shebang refererer til kombinasjonen av hash og utropstegn tegn: #!. Programlaster vil se etter en shebang på første linje i skriptet, og bruk tolken som er angitt i den. En shebang består av følgende syntaks: #!tolk [parametere]. Tolken er det programmet som brukes til å tolke vårt språk. For bash scripting, ville det være / Bin / bash. For eksempel, hvis du vil lage et skript i PHP og kjøre det i konsoll, vil du sikkert bruke / Usr / bin / php (eller banen til PHP-kjørbar på maskinen din) som tolk.

#! / Usr / bin / php  

Ja, det vil faktisk fungere! Er det ikke enkelt? Bare vær sikker på å gjøre filen kjørbar først. Når du gjør dette, vil dette skriptet sende ut PHP-informasjonen som du forventer.

Tips: For å sikre at skriptet ditt fungerer på så mange systemer som mulig, kan du bruke / Bin / env i shebang. Som sådan, i stedet for / Bin / bash, du kan bruke / bin / env bash, som vil fungere på systemer der bash executable ikke er innenfor / bin.


Skrive ut tekst

Utgangen av et skript vil være lik, som du kanskje forventer, hva som kommer ut av kommandoen din. Men hvis vi eksplisitt vil skrive noe på skjermen, kan vi bruke ekko.

#! / bin / bash echo "Hello World"

Kjører dette skriptet vil skrive ut "Hello World" i konsollen.

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

Vi presenterer variabler

Som med alle programmeringsspråk, kan du bruke variabler når du skriver shell-skript.

#! / bin / bash message = "Hello World" ekko $ melding

Denne koden gir nøyaktig samme "Hello World" -melding. Som du kan se, for å tilordne en verdi til en variabel, skriv bare navnet sitt - ekskluder dollarskiltet foran den. Vær også forsiktig med mellomrom; Det kan ikke være noen mellomrom mellom variabelnavnet og likestegnet. Så melding = "Hei" i stedet for melding = 'Hei'

Når du ønsker å bruke en variabel, kan du ta verdien av den, akkurat som vi gjorde i ekko kommando. Forbereder en $ til variabelenes navn returnerer verdien sin.

Tips: Semikoloner er ikke nødvendig i bash scripting. Du kan bruke dem i de fleste tilfeller, men vær forsiktig: de kan ha en annen mening enn det du forventer.


Skrive ut tallene mellom 1 og 100

Fortsett med vårt demo-prosjekt, vi trenger å sykle gjennom alle tallene mellom 1 og 100. For dette må vi bruke en til sløyfe.

#! / bin / bash for nummer i 1 ... 100; gjør ekko $ nummer gjort

Det er flere nye ting verdt å merke seg i dette eksemplet - som forresten skriver ut alle tallene fra 1 til 100, ett tall om gangen.

  • De til syntaks i Bash er: for VARIABLE i RANGE; Gjør COMMAND ferdig.
  • De krøllete armbåndene vil forvandle seg 1 ... 100 inn i et utvalg i vårt eksempel. De brukes også i andre sammenhenger, som vi snart vil se gjennom.
  • gjøre og til er egentlig to separate kommandoer. Hvis du vil plassere to kommandoer på en enkelt linje, må du skille dem på en eller annen måte. En måte er å bruke semikolon. Alternativt kan du skrive koden uten en semikolon ved å flytte gjøre til den følgende linjen.
#! / bin / bash for nummer i 1 ... 100 gjør ekko $ nummer gjort

Den første avgjørelsen

Nå som vi vet hvordan du skriver ut tallene mellom 1 og 100, er det på tide å ta vår første beslutning.

#! / bin / bash for nummer i 1 ... 100; gjør hvis [$ ((tall% 3)) -eq 0]; deretter ekko "Fizz" ellers ekko $ nummer fi gjort

Dette eksemplet vil utgjøre "Fizz" for tall delbart med 3. Igjen må vi takle litt ny syntaks. La oss ta dem en etter en.

  • hvis ... da ... annet ... fi - dette er den klassiske syntaksen for en hvis uttalelse i Bash. Selvfølgelig, den ellers del er valgfritt - men nødvendig for vår logikk i dette tilfellet.
  • hvis COMMAND-RETURN-VALUE; deretter… - hvis vil utføre hvis returverdien av kommandoen er null. Ja, logikken i Bash er null basert, noe som betyr at kommandoer som utføres, avslutter med en kode på 0. Hvis noe går galt, vil et positivt heltall bli returnert. For å forenkle ting: Alt annet enn 0 er vurdert falsk.
  • Matematiske uttrykk i Bash er spesifisert av to parenteser. $ ((Nummer% 3)) vil returnere gjenværende verdi for å dividere variabelen, Nummer, ved 3. Vær oppmerksom på at vi ikke brukte $ inne i parentesen - bare foran dem.

Du lurer kanskje på hvor kommandoen er i vårt eksempel. Er det ikke bare en brakett med et merkelig uttrykk i det? Vel, det viser seg det [ er faktisk en kjørbar kommando. For å leke med dette, kan du prøve følgende kommandoer i konsollen.

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

Tips: En kommandos utgangsverdi blir alltid returnert til variabelen, ? (spørsmålstegn). Det overskrives etter hver ny kommandos kjøring.


Sjekker etter Buzz

Vi har det bra så langt. Vi har "Fizz"; nå la oss gjøre "Buzz" -delen.

#! / bin / bash for nummer i 1 ... 100; gjør hvis [$ ((tall% 3)) -eq 0]; deretter ekko "Fizz" elif [$ ((tall% 5)) -eq 0]; deretter ekko "Buzz" ellers ekko $ nummer fi gjort

Ovenfor har vi introdusert en annen betingelse for delbarhet med 5: elif uttalelse. Dette, selvfølgelig, oversetter til eller hvis, og vil bli utført hvis kommandoen som følger med den returnerer ekte (eller 0). Som du kan observere, de betingede uttalelsene i [] er vanligvis evaluert ved hjelp av parametere, for eksempel -ekv, som står for "likestiller".

For syntaksen, arg1 OP arg2, OP er en av -ekv, -ne, -lt, -le, -gt, eller -ge. Disse aritmetiske binære operatørene returnerer ekte hvis arg1 er lik, ikke lik, mindre enn, mindre enn eller lik, større enn eller høyere enn eller lik arg2, henholdsvis.arg1 og arg2 kan være positive eller negative heltall. - Bash Manual

Når du prøver å sammenligne strenger, kan du bruke den kjente == signere, eller til og med et enkelt like tegn vil gjøre. != avkastning ekte når strengene er forskjellige.


Men koden er ikke helt korrekt

Så langt kjører koden, men logikken er ikke riktig. Når nummeret er delbart med både 3 og 5, vil vår logikk ekko bare "Fizz". La oss endre vår kode for å tilfredsstille det siste kravet til FizzBuzz.

#! / bin / bash for nummer i 1 ... 100; gjør hvis [$ ((tall% 3)) -eq 0]; deretter output = "Fizz" fi hvis [$ ((tall% 5)) -eq 0]; så output = "$ output Buzz" fi hvis [-z $ output]; da ekko $ nummer annet ekko $ output; fi gjort

Igjen har vi fått gjøre en håndfull endringer. Den mest bemerkelsesverdige er introduksjonen av en variabel, og deretter sammenkoblingen av "Buzz" til den, om nødvendig. Strenge i bash er vanligvis definert mellom dobbelte anførselstegn ("). Enkelte anførselstegn kan også brukes, men for enklere sammenkobling er dobbeltrom det bedre valget. Innenfor disse dobbelte sitatene kan du referere til variabler: litt tekst $ variabel annen tekst"vil erstatte $ variabel med innholdet. Når du vil sammenkoble variabler med strenger uten mellomrom mellom dem, kan du foretrekke å sette variabelenes navn i krøllete bånd. I de fleste tilfeller, som PHP, er du ikke pålagt å gjøre det, men det hjelper mye når det gjelder kodens lesbarhet.

Tips: Du kan ikke sammenligne tomme stenger. Det ville returnere en manglende parameter.

Fordi argumenter inni [] behandles som parametere, for "[", de må være forskjellige fra en tom streng. Så dette uttrykket, selv om det er logisk, vil sende ut en feil: [$ output! = ""]. Det er derfor vi har brukt [-z $ utgang], som returnerer ekte hvis strengen har en lengde på null.


Utdrag metode for logisk uttrykk

En måte å forbedre vårt eksempel på er å trekke ut i funksjoner det matematiske uttrykket fra hvis uttalelser, slik som:

#! / bin / bash-funksjonen erDivisibleBy return $ (($ 1% $ 2)) for nummer i 1 ... 100; gjør hvis erDivisibleBy $ nummer 3; så output = "Fizz" fi hvis erDivisibleBy $ nummer 5; så output = "$ output Buzz" fi hvis [-z $ output]; da ekko $ nummer annet ekko $ output; fi gjort

Vi tok uttrykkene som sammenlignet resten med null, og flyttet dem til en funksjon. Enda eliminerte vi sammenligningen med null, fordi null betyr sant for oss. Vi må bare returnere verdien fra det matematiske uttrykket - veldig enkelt!

Tips: En funksjonens definisjon må foregå for å ringe.

I Bash kan du definere en metode som funksjon func_name kommandoer; . Eventuelt finnes det en andre syntaks for å deklarere funksjoner: func_name () kommandoer; . Så, vi kan slippe strengen, funksjon og legg til "()" etter navnet sitt. Jeg personlig foretrekker dette alternativet, som eksemplifisert i eksemplet ovenfor. Det er mer eksplisitt og ligner på tradisjonelle programmeringsspråk.

Du trenger ikke å angi parametrene for en funksjon i Bash. Sender parametere til en funksjon oppnås ved å bare oppregne over dem etter at funksjonssamtalen er adskilt av hvite mellomrom. Ikke legg kommater eller parentes i funksjonsanropet - det virker ikke.

Mottatte parametere blir automatisk tilordnet variabler etter nummer. Den første parameteren går til $ 1, den andre til $ 2, og så videre. Den spesielle variabelen, $ 0 henviser det nåværende skriptets filnavn.

La oss spille med parametere

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

Denne koden vil produsere følgende utgang:

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

La oss analysere kilden, linje for linje.

  • Den siste linjen er funksjonssamtalen. Vi kaller det med tre strengparametere.
  • Den første linjen etter shebang er funksjonsdefinisjonen.
  • Den første linjen i funksjonen gir den første parameteren: "en". Så langt så enkelt.
  • Den andre linjen utdataer nåværende skriptets filnavn. Igjen, veldig enkelt.
  • Den tredje linjen endrer standardkarakter separatoren til bokstaven, "X". Som standard er dette "" (et mellomrom). Slik vet Bash hvordan parametrene skilles.
  • Den fjerde linjen gir en spesiell variabel, $ @. Den representerer alle parametrene som et enkelt ord, akkurat som angitt i funksjonssamtalen.
  • Den endelige linjen gir en annen spesiell variabel, $ *. Den representerer alle parametrene, tatt en-for-en og sammenkalt med første bokstav i IFS-variabelen. Derfor er resultatet oneXtwoXthre.

Returstrenger fra funksjoner

Som nevnt tidligere, kan funksjoner i Bash bare returnere heltall. Som sådan skriver du returnere "en streng" ville være ugyldig kode. Likevel, i mange situasjoner, trenger du mer enn bare en null eller en. Vi kan refactor vårt FizzBuzz eksempel slik at i til uttalelse, vi skal bare ringe et funksjonsanrop.

#! / bin / bash-funksjonen erDivisibleBy return $ (($ 1% $ 2)) funksjon fizzOrBuzz if isDivisibleBy $ 1 3; så output = "Fizz" fi hvis erDivisibleBy $ 1 5; så output = "$ output Buzz" fi hvis [-z $ output]; da ekko $ 1 annet ekko $ output; fi for nummer i 1 ... 100; gjør fizzOrBuzz $ nummer gjort

Vel, dette er det første trinnet. Vi har nettopp hentet hele koden til en funksjon, kalt fizzOrBuzz, og deretter erstattet $ nummer med $ 1. Imidlertid skjer all utmatning i fizzOrBuzz funksjon. Vi ønsker å sende ut fra til loop med en ekko setning, slik at vi kan prepend hver linje med en annen streng. Vi må fange fizzOrBuzz funksjonens utgang.

# [...] for nummer i 1 ... 100; gjør ekko "-'fizzOrBuzz $ nummer '" fizzBuzzer = $ (fizzOrBuzz $ nummer) ekko "- $ fizzBuzzer" gjort

Vi har oppdatert vår til loop bare litt (ingen andre endringer). Vi har nå egget alt to ganger på to forskjellige måter for å eksemplifisere forskjellene mellom de to løsningene til det samme problemet.

Den første løsningen for å fange utgangen av en funksjon eller en annen kommando er å bruke backticks. I 99% av tilfellene vil dette fungere helt fint. Du kan bare referere til en variabel innenfor backticks etter navnene deres, som vi gjorde med $ nummer. De første linjene i utgangen bør nå se ut som:

csaba @ csaba ~ / Personal / Programming / NetTuts / Grunnleggende om BASH Scripting / Kilder $ ./fizzBuzz.sh -1 -1 -2 -2 -Fizz -Fizz -4 -4 -Buzz -Buzz -Fizz -Fizz -7 -7

Som du kan se, blir alt duplisert. Samme utgang.

For den andre løsningen har vi valgt å først tildele returverdi til en variabel. I den oppgaven brukte vi $ (), som i dette tilfellet forgir skriptet, kjører koden og returnerer sin utgang.


;, && og ||

Husker du at vi brukte semikolon her og der? De kan brukes til å utføre flere kommandoer skrevet på samme linje. Hvis du skiller dem fra semikolon, blir de rett og slett henrettet.

Et mer sofistikert tilfelle er å bruke && mellom to kommandoer. Ja, det er en logisk AND; det betyr at den andre kommandoen vil bli utført bare hvis den første kommer tilbake ekte (det går ut med 0). Dette er nyttig; vi kan forenkle hvis uttalelser i disse kortene:

#! / bin / bash-funksjonen erDivisibleBy return $ ($ 1% $ 2)) funksjon fizzOrBuzz isDivisibleBy $ 1 3 && output = "Fizz" erDivisibleBy $ 1 5 && output = "$ output Buzz" hvis [-z $ utgang ]; da ekko $ 1 annet ekko $ output; fi for nummer i 1 ... 100; gjør ekko "-'fizzOrBuzz $ nummer '" ferdig

Som vår funksjon, isDivisibleBy returnerer en riktig returverdi, vi kan da bruke && å angi variabelen vi ønsker. Hva er etter? && vil bli utført bare hvis tilstanden er ekte. På samme måte kan vi bruke || (dobbeltrørskarakter) som en logisk ELLER. Her er et raskt eksempel nedenfor.

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

Siste tanker

Så det gjør det for denne opplæringen! Jeg håper at du har plukket opp en håndfull nye tips og teknikker for å skrive dine egne Bash-skript. Takk for at du leser, og hold deg oppdatert for mer avanserte artikler om dette emnet.