Een shellscript schrijven van Scratch

Het schrijven van shellscripts kan nogal ontmoedigend zijn, vooral omdat de shell niet de meest vriendelijke talen is om te gebruiken. Ik hoop echter om u in deze tutorial te laten zien dat shell scripting eigenlijk niet zo moeilijk of eng is als u zou verwachten.

Voor deze zelfstudie schrijven we een script dat het gebruik van het Jasmine-testraamwerk een beetje gemakkelijker maakt. Eigenlijk zou ik dit script vandaag niet gebruiken; Ik zou Grunt.js of iets dergelijks gebruiken. Ik schreef dit script echter voordat Grunt in de buurt was, en ik merkte dat het schrijven ervan een uitstekende manier bleek te zijn om comfortabeler te worden met shell-scripting, dus daarom gebruiken we het.

Eén opmerking: deze tutorial is los geassocieerd met mijn aanstaande Tuts + Premium-cursus 'Advanced Command Line Techniques'. Om meer te weten te komen over vrijwel alles in deze tutorial, blijf op de hoogte van de release van die cursus. Hierna wordt deze tutorial 'de cursus' genoemd.

Dus, ons script, dat ik bel jazz-, zal vier hoofdkenmerken hebben:

  • Het downloadt Jasmine van internet, pakt het uit en verwijdert de voorbeeldcode.
  • Het maakt JavaScript-bestanden en de bijbehorende spec-bestanden en vult ze vooraf in met een beetje sjablooncode.
  • Het opent de tests in de browser.
  • Het zal de helptekst weergeven, die het bovenstaande schetst.

Laten we beginnen met het scriptbestand.


Stap 1 - Het bestand maken

Het schrijven van een shellscript is alleen nuttig als je het vanaf de terminal kunt gebruiken; om uw aangepaste scripts op de terminal te kunnen gebruiken, moet u ze in een map plaatsen die zich in de terminal bevindt PAD variabele (u kunt uw PAD variabel door te rennen echo $ PATH). Ik heb een gemaakt ~ / Bin map (waar ~ is de homedirectory) op mijn computer, en dat is waar ik graag aangepaste scripts bijhoud (als je hetzelfde doet, moet je het toevoegen aan je pad). Dus, maak gewoon een bestand, genaamd jazz-, en zet het in je map.

Natuurlijk moeten we dat bestand ook uitvoerbaar maken; anders kunnen we het niet uitvoeren. We kunnen dit doen door het volgende commando uit te voeren:

 chmod + x jazz

Nu we het script echt kunnen uitvoeren, laten we er een heel belangrijk deel aan toevoegen. Alle shellscripts zouden met een shebang moeten beginnen). Zoals Wikipedia zegt, zou dit de eerste regel van het script moeten zijn; het geeft aan met welke tolk, of shell, dit script moet worden uitgevoerd. We gaan gewoon een standaard basishell gebruiken:

 #! / Bin / sh

Oké, met al die instellingen staan ​​we klaar om te beginnen met het schrijven van de code.


Stap 2 - De scriptstroom schetsen

Eerder heb ik gewezen op de verschillende kenmerken van ons shellscript. Maar hoe weet het script welke functie moet worden uitgevoerd? We zullen een combinatie van een shell-parameter en een case-statement gebruiken. Wanneer u het script vanaf de opdrachtregel uitvoert, gebruiken we een subopdracht, zoals deze:

 jazz init jazz creëer SomeFile jazz run jazz help

Dit zou er bekend uit moeten zien, vooral als je Git hebt gebruikt:

 git init git status git commit

Gebaseerd op die eerste parameter (in het, creëren, rennen, helpen), zal onze casusverklaring beslissen wat te lopen. We hebben echter een standaardkwestie nodig: wat gebeurt er als er geen eerste parameter wordt gegeven of krijgen we een niet-herkende eerste parameter? In die gevallen tonen we de helptekst. Dus laten we beginnen!


Stap 3 - De helptekst schrijven

We beginnen met de als verklaring die controleert op onze eerste parameter:

 als [$ 1] dan # do stuff else # show help fi

Misschien ben je in het begin een beetje in de war, omdat het een schelp is als verklaring is behoorlijk verschillend van een "gewone" programmeertaal als uitspraak. Om een ​​beter begrip ervan te krijgen, bekijk de screencast op voorwaardelijke uitspraken in de cursus. Deze code controleert de aanwezigheid van een eerste parameter ($ 1); als het er is, voeren we het uit dan code; anders, we zullen de helptekst laten zien.

Het is een goed idee om het afdrukken van de hulptekst in een functie in te pakken, omdat we dit meer dan eens moeten noemen. We moeten de functie definiëren voordat deze wordt aangeroepen, dus we zetten hem bovenaan. Ik vind dit leuk, want nu, zodra ik het bestand open, zie ik de documentatie voor het script, wat een nuttige herinnering kan zijn bij het terugkeren naar code die je al een tijdje niet hebt gezien. Zonder verder oponthoud, hier is de helpen functie:

 function help () echo "jazz - Een eenvoudig script dat het gebruik van het Jasmine-testraamwerk in een op zichzelf staand project een beetje eenvoudiger maakt." echo "echo" jazz init - voeg jasmine toe aan het project "; echo" jazz create FunctionName - create ./src/FunctionName.js ./spec/FunctionNameSpec.js "; echo" jazz run - voert tests uit in browser ";

Vervang dat gewoon # hulp laten zien functie met een oproep naar de helpen functie.

 help anders fi

Stap 4 - De case-verklaring schrijven

Als er een eerste parameter is, moeten we uitzoeken wat het is. Hiervoor gebruiken we een geval uitspraak:

 vraag "$ 1" in init) ;; create) ;; rennen) ;; *) helpen ;; esac

We geven de eerste parameter door aan de geval uitspraak; dan moet het overeenkomen met een van de vier dingen: "init", "create", "run", of onze wildcard, standaard case. Merk op dat we geen expliciete "hulp" -case hebben: dat is gewoon onze standaardkwestie. Dit werkt, omdat iets anders dan "init", "create" en "run" geen opdrachten zijn die we herkennen, dus het moet de helptekst krijgen.

Nu zijn we klaar om de functionele code te schrijven en we zullen beginnen jazz init.


Stap 5 - Jasmijn bereiden met jazz init

Alle code die we hier schrijven, zal binnen onze in het) zaak, uit de case-statement hierboven. De eerste stap is om de stand-alone versie van Jasmine, die wordt geleverd in een zipbestand, daadwerkelijk te downloaden:

 echo "Jasmine downloaden ..." curl -sO $ JASMINE_LINK

We geven eerst een klein berichtje en daarna gebruiken we Krul om de zip te downloaden. De s vlag maakt het stil (geen uitvoer) en de O flag slaat de inhoud van de zip op in een bestand (anders zou het naar standaard uitpipen). Maar wat is dat $ JASMINE_LINK variabele? Wel, je zou de eigenlijke link naar het zip-bestand daar kunnen plaatsen, maar ik plaats het om twee redenen liever in een variabele: ten eerste, het weerhoudt ons een deel van het pad te herhalen, zoals je in een minuut zult zien. Ten tweede maakt het met die variabele aan de bovenkant van het bestand het gemakkelijk om de versie van Jasmine die we gebruiken te veranderen: verander gewoon die ene variabele. Hier is die variabele verklaring (ik zet het buiten de als verklaring, bij de top):

 JASMIME_LINK = "http://cloud.github.com/downloads/pivotal/jasmine/jasmine-standalone-1.3.1.zip"

Denk eraan, geen spaties rond het gelijkteken op die regel.

Nu we ons zipbestand hebben, kunnen we het uitpakken en de inhoud voorbereiden:

 unzip -q basename $ JASMINE_LINK rm -rf basename $ JASMINE_LINK src / *. js spec / *. js

In twee van deze regels gebruiken we basename $ JASMINE_LINK; de basename commando reduceert gewoon een pad naar de basisnaam: dus path / to / file.zip wordt rechtvaardig file.zip. Dit stelt ons in staat om dat te gebruiken $ JASMINE_LINK variabele om naar ons lokale zipbestand te verwijzen.

Nadat we het zip-bestand hebben uitgepakt, verwijderen we dat zipbestand en alle JavaScript-bestanden in de src en spec directories. Dit zijn de voorbeeldbestanden die Jasmine bevat, en we hebben ze niet nodig.

Vervolgens hebben we een probleem met alleen de Mac om mee om te gaan. Wanneer u iets van internet downloadt op een Mac en u probeert het voor het eerst uit te voeren, wordt u standaard gevraagd om te bevestigen dat u het wilt uitvoeren. Dit komt door het uitgebreide attribuut com.apple.quarantine dat Apple het bestand aanzet. We moeten dit kenmerk verwijderen.

 if which xattr> / dev / null && ["xattr SpecRunner.html"=" com.apple.quarantine "] gevolgd door xattr -d com.apple.quarantine SpecRunner.html fi

We beginnen met het controleren van de aanwezigheid van de xattr commando, omdat het niet bestaat op sommige Unix-systemen (ik weet het niet zeker, maar het kan een Mac-programma zijn). Als je de course screencast op conditionals hebt bekeken, weet je dat we elke opdracht kunnen doorgeven als; als het een exit-status heeft van iets anders dan 0, het is fout. Als welke vindt het xattr opdracht, hiermee wordt afgesloten 0; anders zal het afsluiten met 1. In elk geval, welke zal wat output weergeven; we kunnen voorkomen dat dit wordt weergegeven door het om te leiden naar / Dev / null (dit is een speciaal bestand dat alle geschreven gegevens weggooit).

Dat dubbele amandand is een Booleaanse AND; het is er voor de tweede voorwaarde die we willen controleren. Dat wil zeggen, doet het SpecRunner.html hebben dat attribuut? We kunnen gewoon de xattr opdracht in het bestand en vergelijk de uitvoer met de reeks die we verwachten. (We kunnen niet verwachten dat het bestand het attribuut heeft, omdat je deze functie in Mac OS X eigenlijk kunt uitschakelen, en we zullen een foutmelding krijgen wanneer we proberen het uit te schakelen als het bestand niet over het attribuut beschikt).

Dus indien xattr is gevonden en het bestand heeft het attribuut, we zullen het verwijderen, met de d (voor verwijderen) vlag. Vrij eenvoudig, toch??

De laatste stap is om te bewerken SpecRunner.html. Momenteel bevat het scripttags voor de voorbeeld JavaScript-bestanden die we hebben verwijderd; we moeten ook die scripts-tags verwijderen. Ik weet toevallig dat die scripttags de regels 12 tot 18 in de bestanden overspannen. Dus we kunnen de stream-editor gebruiken sed om die regels te verwijderen:

 sed -i "" '12, 18d 'SpecRunner.html echo "Jasmine geïnitialiseerd!"

De ik vlag vertelt sed om het bestand op zijn plaats te bewerken, of om de uitvoer van de opdracht op te slaan naar hetzelfde bestand dat we hebben doorgegeven; de lege string na de vlag betekent dat we niet willen sed om een ​​back-up van het bestand voor ons te maken; als je dat wilde, kon je gewoon een bestandsextensie in die string plaatsen (zoals .bak, te krijgen SpecRunner.html.bak).

Ten slotte laten we de gebruiker weten dat Jasmine geïnitialiseerd is. En dat is het voor ons jazz init commando.


Stap 6 - Bestanden maken met jazz creëren

Vervolgens laten we onze gebruikers JavaScript-bestanden en hun bijbehorende spec-bestanden maken. Dit gedeelte van de code gaat in het gedeelte 'create' van de geval verklaring die we eerder hebben geschreven.

 als [$ 2] dan # maak bestanden anders echo "vermeld dan een naam voor het bestand" fi

Tijdens gebruik jazz creëren, we moeten een naam voor het bestand opnemen als de tweede parameter: jazz maakt View, bijvoorbeeld. We zullen dit gebruiken om te creëren src / View.js en spec / ViewSpec.js. Dus als er geen tweede parameter is, zullen we de gebruiker eraan herinneren om er een toe te voegen.

Als er een bestandsnaam is, beginnen we met het maken van die twee bestanden (in de dan deel hierboven):

 echo "function $ 2 () \ n \ n"> src / $ 2.js echo "beschrijven ('$ 2', function () \ n \ n);" > spec / $ 2Spec.js

Je kunt natuurlijk alles in je stoppen src het dossier. Ik doe hier iets basaals; zo jazz maakt View zal maken src / View.js hiermee:

 functie Weergave () 

Dat zou je eerst kunnen vervangen echo regel hiermee:

 echo "var $ 2 = (function () \ n \ tvar $ 2Prototype = \ n \ n \ t; \ n \ n \ treturn \ n \ t \ tcreate: function (attrs) \ n \ t \ t \ tvar o = Object.create ($ 2Prototype); \ n \ t \ t \ textend (o, attrs); \ n \ t \ t \ t \ treturn o; \ n \ t \ t \ n \ t; \ n ());" > src / $ 2.js

En dan jazz maakt View zal dit resulteren in:

 var View = (function () var ViewPrototype = ; return create: function (attrs) var o = Object.create (ViewPrototype); extend (o, attrs); return o;; ()) ;

Dus, echt, je verbeelding is de limiet. Natuurlijk wil je dat het spec-bestand de standaard Jasmine spec-code is, wat ik hierboven heb; maar je kunt dat ook aanpassen zoals jij ook leuk vindt.

De volgende stap is om de scripttags voor deze bestanden toe te voegen SpecRunner.html. In eerste instantie lijkt dit misschien lastig: hoe kunnen we programmatisch regels aan het midden van een bestand toevoegen? Nogmaals, het is sed dat doet het werk.

 sed -i "" "11a \\ \\  "SpecRunner.html

We starten net zoals eerder: in-place bewerken zonder back-up. Dan ons commando: op regel 11 willen we de volgende twee regels toevoegen. Het is belangrijk om aan de twee nieuwe regels te ontsnappen, zodat ze in de tekst verschijnen. Zoals je ziet, voegt dit gewoon die twee scripttags in, precies wat we nodig hebben voor deze stap.

We kunnen eindigen met wat output:

 echo "Gemaakt:" echo "\ t- src / $ 2.js" echo "\ t- spec / $ 2Spec.js" echo "Bewerkt:" echo "\ t- SpecRunner.html"

En dat is jazz creëren!


Stap 7 - De specificaties uitvoeren met jazz run

De laatste stap is om de tests daadwerkelijk uit te voeren. Dit betekent het openen van de SpecRunner.html bestand in een browser. Er is hier een beetje een voorbehoud. Op Mac OS X kunnen we de Open commando om een ​​bestand te openen in zijn standaard programma; dit zal niet werken op een ander OS, maar zo doe ik het hier. Helaas is er geen echt platformoverschrijdende manier om dit te doen, waarvan ik weet. Als u dit script onder Cygwin in Windows gebruikt, kunt u dit gebruiken cygstart in plaats van Open; Probeer anders googlen "[uw OS] shellscript open browser" en zie wat u verzint. Helaas hebben sommige versies van Linux (althans Ubuntu, in mijn ervaring) een Open commando dat is voor iets heel anders. Dit alles om te zeggen dat uw kilometerstand met het volgende kan variëren.

als ["'welke open'" = '/ usr / bin / open'] dan opent SpecRunner.html anders echo "Open SpecRunner.html in je browser" fi

Inmiddels weet u precies wat dit doet: als we dat hebben Open, we zullen openen SpecRunner.html, anders drukken we een bericht af met de gebruiker om het bestand in de browser te openen.

Oorspronkelijk dat als conditie zag er als volgt uit:

indien open> / dev / null

Zoals we deden met xattr, het heeft gewoon gecontroleerd op het bestaan ​​van Open; echter, omdat ik erachter kwam dat er een andere is Open commando op Linux (zelfs op mijn Ubuntu-server, die zelfs geen browser kan openen!), ik dacht dat het misschien beter was om het pad van de Open programma, aangezien Linux er is / Bin / geopend (opnieuw, althans op Ubuntu-server).

Al deze extra woordelijkheid over Open klinkt misschien als een excuus voor mijn gebrek aan een goede oplossing, het geeft eigenlijk iets belangrijks aan over de opdrachtregel. Vergis u niet om de terminal te begrijpen met begrip van de configuratie van een computer. Deze tutorial en de bijbehorende cursus hebben je een beetje meer geleerd over de Bash-shell (en de Z-shell), maar dat betekent niet dat elke computer die je gebruikt hetzelfde zal worden geconfigureerd; er zijn veel manieren om nieuwe opdrachten (of verschillende versies van opdrachten) te installeren en om opdrachten te verwijderen. Waarschuwingsteken.

Wel, dat is het hele script! Hier is het weer, alles bij elkaar:

 #! / bin / sh-functie help () echo "jazz - Een eenvoudig script dat het gebruik van het Jasmine-testraamwerk in een op zichzelf staand project een beetje eenvoudiger maakt." echo "" echo "jazz init - voeg jasmijn toe aan het project"; echo "jazz create FunctionName - create ./src/FunctionName.js ./spec/FunctionNameSpec.js"; echo "jazz run - voert tests uit in browser";  JASMIME_LINK = "http://cloud.github.com/downloads/pivotal/jasmine/jasmine-standalone-1.3.1.zip" als [$ 1] en vervolgens case "$ 1" in init) echo "Downloaden van Jasmine ..." krullen - sO $ JASMIME_LINK unzip -q 'basename $ JASMIME_LINK' rm 'basenaam $ JASMIME_LINK' src / *. js spec / *. js als welke xattr> / dev / null && ["'xattr SpecRunner.html'" = "com.apple .quarantine "] dan xattr -d com.apple.quarantine SpecRunner.html voltooid -i" "" 12,18d "SpecRunner.html echo" Jasmine geïnitialiseerd! " ;; create) als [$ 2] dan echo "function $ 2 () \ n \ n"> ./src/$2.js echo "omschrijven ('$ 2', function () \ nit ('runs'); \ n );" > ./spec/$2Spec.js sed -i "" "11a \\ \\  "SpecRunner.html echo" Gemaakt: "echo" \ t- src / $ 2.js "echo" \ t- spec / $ 2Spec.js "echo" Bewerkt: "echo" \ t- SpecRunner.html "else echo" alsjeblieft voeg een naam toe voor het bestand 'fi ;; "run") als ["' open '" =' / usr / bin / open '] open ./SpecRunner.html anders echo "Open SpecRunner.html in uw browser "fi ;; *) help;; esac else help; fi

Nou, ga door, probeer het eens!

 mkdir project cd project jazz init jazz creëren Dog # edit src / Dog.js en spec / DogSpec.js jazz run

Trouwens, als je wat meer plezier wilt hebben met dit project, kun je het vinden op Github.


Conclusie

Dus daar heb je het! We hebben zojuist een shellscript van een gemiddeld niveau geschreven; dat was niet zo erg, toch? Vergeet niet om op de hoogte te blijven van mijn aankomende Tuts + Premium-cursus; u zult veel meer leren over veel van de technieken die in dit artikel worden gebruikt, evenals talloze anderen. Veel plezier op de terminal!