"Shell" C:ssä: komentotulkin kirjoittaminen Unixille. Hei maailma! Yksinkertainen varmuuskopiointijärjestelmä. Kuka sitä tarvitsee

    Linux-perheen käyttöjärjestelmät sekä kaikki muut käyttöjärjestelmät vaativat vuorovaikutusrajapinnan tietokonejärjestelmän komponenttien ja loppukäyttäjän välillä, toisin sanoen ohjelmistotason, joka antaa komentoja. ja parametrit haluttujen tulosten saavuttamiseksi. Sellainen ohjelmataso sai nimen "kuori" tai klo Englannin kieli - kuori.

Mikä on kuori?

Komentotulkki ( kuori) tarjoaa vuorovaikutusta käyttäjän ja ympäristön välillä käyttöjärjestelmä Linux. Hän on erikoistunut ohjelmistotuote, joka varmistaa komentojen suorittamisen ja niiden suorittamisen tulosten saamisen, tai hyvin yksinkertaisesti sanottuna kuori on ohjelma, joka on suunniteltu varmistamaan muiden ohjelmien suorittaminen käyttäjän pyynnöstä. Esimerkki komentotulkista voi olla esimerkiksi komentotulkki command.com käyttöjärjestelmä MS DOS tai shell lyödä Unix/Linux käyttöjärjestelmät.

Kaikilla kuorilla on samanlaiset toiminnot ja ominaisuudet päätarkoituksensa mukaisesti - suorittaa käyttäjän komentoja ja näyttää niiden suorituksen tulokset:

Komentorivin tulkinta.

Pääsy komentoihin ja niiden suorittamisen tuloksiin.

Tuki muuttujille, erikoismerkeille ja varatut sanat.

Tiedostojen käsittely, vakiosyöttö- ja tulostustoiminnot.

Toteutus erikoiskieli kuoriohjelmointi.

    Käyttöjärjestelmille Unix-perhe/ Linux, on mahdollista käyttää useita erilaisia ​​kuoria, jotka eroavat ominaisuuksiltaan ja vuorovaikutusmenetelmiltä järjestelmän kanssa. Yleisimmät kuoret ovat

sh-kuori Bourne, klassinen kuori Unix-käyttöjärjestelmälle

lyödä kuori Bourne jälleen(GNU Bourne-Again SHell). Ehkä yleisin kuori tällä hetkellä Linux-käyttöjärjestelmäympäristössä.

ksh-kuori Korn, suunniteltu kuorikehitykseen Bourne komentorivihistorialla ja kyvyllä muokata komentoja.

csh-kuori C, käyttämällä suositun ohjelmointikielen syntaksia C

tcsh- kuoriversio C interaktiivisella komentorivimuokkauksella.

Järjestelmään voidaan asentaa useita erilaisia ​​kuoria, ja jokainen käyttäjä voi käyttää omaa oletuskuoriaan. Kaikki tämä tapahtuu tietysti automaattisesti lataus- ja käyttäjän rekisteröintiprosessin aikana.

    Linux-perheen käyttöjärjestelmien latausprosessin aikana järjestelmäytimen lataamisen jälkeen järjestelmä siirtyy interaktiiviseen tilaan - käyttäjän ja käyttöjärjestelmän väliseen vuorovaikutustilaan. Linuxissa ensimmäinen käynnistyksen aikana käynnistetty prosessi on init-ohjelma. sen sisällä, joka lukee määritystiedoston sisällön /etc/inittab, määrittää järjestelmässä käytettävissä olevien päätteiden luettelon ja ominaisuudet sekä kutsuu interaktiivisen kirjautumisohjelman Getty, joka kehottaa sinua antamaan käyttäjätunnuksesi. Kun olet syöttänyt käyttäjätunnuksen ja salasanan, ohjelma Getty kutsuu ohjelman Kirjaudu sisään, joka tarkistaa kelvollisuuden tili, siirtyy käyttäjän kotihakemistoon ja siirtää ohjauksen istunnon käynnistysohjelmalle, joka on yleensä käyttäjän shell-ohjelma, jonka maku määräytyy tiedoston sisällön mukaan /etc/passwd tälle tilille. Esimerkiksi:

user1:x:508:511::/home/user1:/bin/sh
interbase:x:510:511::/home/interbase:/bin/csh
apb:x:511:513:apb:/home/apb:/bin/bash

Kuten tiedoston sisällöstä näkyy /etc/passwd, käyttäjälle käyttäjä1 kuori laukaistaan sh(Bourne-kuori), käyttäjälle interbase-kuori csh(C-kuori) ja käyttäjälle apb-kuori lyödä(Bourne Again) Kun komentotulkki käynnistyy, näytölle tulee komentokehote (yleensä dollarimerkin muodossa $ jos työ tehdään tavallisen käyttäjätilin tai punnan yhteydessä # , jos komentotulkkia käytetään pääkäyttäjän tunnuksella ( juuri).

Kun komentotulkista poistutaan, järjestelmän ydin palauttaa ohjelman ohjauksen sen sisällä, joka käynnistää kirjautumisprosessin uudelleen ja näyttää käyttäjätunnuskehotteen päätelaitteessa. Kuoresta poistuminen voidaan tehdä kahdella tavalla:

Joukkueen kautta poistu käyttäjän suorittama

Kun kuoriprosessi vastaanottaa signaalin tappaa, jonka ydin lähettää, esimerkiksi kun järjestelmä käynnistetään uudelleen.

Komentorivin tulkinta.

    Käyttäjän syöttöä komentotulkkikehotteeseen kutsutaan yleensä komentorivi tai tiimi. Linux-komento on merkkijono komennon nimestä ja argumenteista, jotka on erotettu välilyönneillä. Argumentit tarjoavat komennon lisäparametreja, jotka määrittävät sen toiminnan. Useimmiten käytetään argumentteina vaihtoehtoja Ja nimet tiedostot ja hakemistot. Esimerkiksi komentorivi

ls -l tiedosto01 tiedosto02

Sisältää ls-komennon, -l-vaihtoehdon ja kaksi tiedostonimeä tiedosto01 tiedosto02.

Useita vaihtoehtoja käytettäessä niitä voidaan yhdistää. Esimerkiksi seuraavat komentovaihtoehdot ovat identtisiä:

Ls -l -d
ls -ld

Komentot, jotka ovat osa kuorta, kutsutaan sisäänrakennettu. Tällaisia ​​komentoja ovat esimerkiksi cd, if, case jne. Luonnollisesti sisäänrakennetut komennot voivat poiketa erilaisia ​​vaihtoehtoja kuoret. Sisäänrakennettujen komentojen lisäksi on mahdollista käyttää ohjelmistomoduulit, jotka ovat yksittäisiä suoritettavia tiedostoja tai tiedostoja käsikirjoituksia tai skenaarioita- tavalliset tekstitiedostot, jotka sisältävät peräkkäin suoritettuja rivejä komentotulkkikomennoilla. Jotkut skriptit (skriptit) voivat suorittaa Linux-prosessit, kuten tehtävien ajoitus cron. Tehtävien ajoitus on yleensä suunniteltu automaattinen suoritus ajoitetut järjestelmänhallintatehtävät. Tehtävät cron ovat komentoja tai komentosarjoja ja ne suoritetaan automaattisesti ilman ihmisen väliintuloa, ja ne voidaan suorittaa eri käyttäjätilien yhteydessä. Tapauksessa, jossa ajoitustehtävä sisältää komentosarjan suorittamisen, syntyy ongelma valita komentotulkki, joka pitäisi käynnistää lapsiprosessina cron komentotiedostojen komentojen käsittelyyn - loppujen lopuksi kuori voi olla mikä tahansa, ja komentosarjan syntaksi vaatii yleensä sen tietyn kuoren käyttöä, jolle se on kirjoitettu. Tämän ongelman poistamiseksi Linux-käyttöjärjestelmissä on tapana ilmoittaa komentosarjan ensimmäisellä rivillä sen suorittamiseen tarvittavan kuoren tyyppi muodossa:

#!/bin/bash- kuorelle lyödä

#!/bin/sh- kuorelle sh

Merkki # on merkki kommentista, eikä sitä seuraavia merkkejä tulkita komennona. Tämän tekniikan avulla voit määrittää nimenomaisesti, mitä komentotulkkia tulee käyttää seuraavan tiedoston sisällön käsittelemiseen. Jos komentosarja ei sisällä merkintää, joka nimenomaisesti määrittelee vaaditun komentotulkin, käytetään sen tilin asetuksia, jossa komentosarja suoritetaan. Tässä tapauksessa on mahdollista, että komentotulkille kirjoitettu komentosarja, esim. tch siirretään kuoreen suorittamista varten lyödä, mikä tekee sen suorittamisen mahdottomaksi.

Kun suoritat komentoja tai skriptejä, käytä ympäristömuuttujat(englanniksi - ympäristöön, joiden arvot kuvaavat ohjelmistoympäristöä, jossa komennot suoritetaan. Tällaiset muuttujat voivat sisältää Yleiset asetukset järjestelmä-, graafiset tai komentotulkin parametrit, suoritettavien tiedostojen polut jne. Ympäristömuuttujien arvot asetetaan järjestelmätasolla (kaikille käyttäjille) ja tietylle käyttäjätasolle. Ympäristömuuttujien asettamiseen järjestelmätasolla käytetään tiedostojen sisältöä:

/etc/profile- asettaa muuttujat vain komentotulkeille. Voi suorittaa mitä tahansa komentosarjoja Bourne-kuoren kanssa yhteensopivissa kuorissa.

/etc/bash.bashrc- asettaa muuttujat vain interaktiivisille kuorille. Se suorittaa myös bash-skriptejä.

/etc/environment- PAM-env-moduulin käyttämä. Tässä tiedostossa voidaan määrittää vain pareja nimi=arvo.

Jokaisella näistä tiedostoista on oma sovellus, joten sinun on valittava huolellisesti tarkoituksiinsa sopiva. Jos esimerkiksi haluat lisätä mukautetun hakemiston ~/bin muuttujaksi PATH kaikille käyttäjille, aseta seuraava koodi johonkin järjestelmätiedostot ympäristön alustus (/etc/profile tai /etc/bash.bashrc):

# Jos käyttäjätunnus on suurempi tai yhtä suuri kuin 1000 ja siinä on ~/bin-hakemisto ja se

#ei ole aiemmin lisätty PATH-muuttujaan,

# vie ~/bin kohteeseen $PATH.

Jos [[ $UID -ge 1000 && -d $HOME/bin && -z $(echo $PATH | grep -o $HOME/bin)

Vie PATH=$HOME/bin:$(PATH)

Tyypillisesti leikkaussaleissa Linux-järjestelmät, Palvelutileissä käytetään käyttäjätunnusta alle 1000 tai alle 500. Tässä esimerkissä ympäristömuuttuja asetetaan kaikille järjestelmän paikallisille käyttäjille, joiden tunnus on 1000 tai suurempi.

Jos sinun on vaihdettava tietyn käyttäjän ympäristöä, muokkaa käyttäjän ympäristön sisältöä:

- ~/.bash_profile, ~/.bash_login ja niin edelleen. - shell-alustustiedostot käyttäjän kotihakemistosta.

- ~/.profiili- käyttäjäprofiilin alustustiedosto. Monet kuoret käyttävät sitä ympäristömuuttujien määrittämiseen.

~/.pam_environment- /etc/environment-tiedoston mukautettu analogi, jota PAM-env-moduuli käyttää.

Esimerkiksi lisätäksesi käyttäjän hakemiston ~/bin muuttujan määrittämien suoritettavien tiedostojen hakupolkuun PATH esimerkiksi tiedostoon ~/.profiili laita rivi:

vie PATH="$(PATH):/home/user/bin"

Ympäristömuuttujien asettamiseen graafisille sovelluksille käytetään käyttäjän graafisen ympäristön asetustiedostojen sisältöä ~/.xinitrc

Useammin ympäristömuuttujien arvot asetetaan nykyiselle käyttäjäistunnolle. Esimerkiksi mukautetun hakemiston lisääminen ~/bin suoritettavien tiedostojen hakupolussa:

vie PATH=~/bin:$PATH

Uusi muuttujan arvo PATH kestää vain, kunnes nykyinen käyttäjäistunto päättyy.

Voit tarkastella muuttujan arvoa komennolla echo $muuttuja, Esimerkiksi:

echo $PATH

Tällä hetkellä yleisin kuori, kuten edellä mainittiin, on lyödä. Tämä johtuu ensisijaisesti siitä, että kuori lyödä On sh- yhteensopiva komentotulkki lisättynä hyödyllisiä ominaisuuksia Korn kuorista ( ksh) ja C-kuori ( csh). Kuori lyödä voi ajaa useimpia komentosarjoja, jotka on kirjoitettu shell-ohjelmointikielellä ilman muutoksia sh ja yrittää päästä mahdollisimman lähelle standardia POSIX, joka johti moniin parannuksiin sekä ohjelmointiin että interaktiiviseen käyttöön. Nykyaikaisessa toteutuksessa lyödä on komentorivin muokkaustila, rajoittamaton koko komentohistoria, tehtävienhallintatyökalut, kyky käyttää aliaksia, laaja luettelo sisäänrakennetuista komennoista, komentotulkkitoiminnot jne. Yleisesti, lyödä sopii parhaiten keskivertokäyttäjän tarpeisiin, mikä on tehnyt siitä eniten käytetyn Linux-ympäristössä.

Käynnistyksessä lyödä ilman komentoriviparametreja komentotulkki käynnistyy interaktiivisessa tilassa ja näyttää komentokehotteen näytöllä. Vuorovaikutteinen kuori tyypillisesti lukee dataa käyttäjän päätteestä ja kirjoittaa dataa samaan päätteeseen, jolloin vakiosyöttölaite on näppäimistö ja vakiotulostuslaite näyttö. Käyttäjä syöttää komentoja näppäimistöllä, ja niiden suorittamisen tulos näkyy näytöllä.

Monet ihmiset ajattelevat, että miljoonien ihmisten käyttämän ohjelman tekeminen on erittäin vaikeaa. Jokaisen, jopa monimutkaisimmankin tuotteen takana on kuitenkin aina yksinkertainen idea. Yksi niistä on komentokulli tai -kuori. Tässä artikkelissa näytämme, kuinka kirjoitetaan yksinkertaistettu Unix-kuori C-kielellä.

Neuvoja Älä lähetä tai käytä (edes muunnetussa muodossa) alla olevaa koodia kotiprojektina koulussa tai yliopistossa. Monet opettajat tietävät alkuperäisen artikkelin ja saavat sinut kiinni huijaamisesta.

Kuoren elinkaari

Kuori suorittaa kolme päätoimintoa elinkaarensa aikana:

  1. Alustus: Tässä vaiheessa se lukee ja suorittaa määritystiedostonsa. Ne muuttavat hänen käyttäytymistään.
  2. Tulkinta: Tämän jälkeen komentotulkki lukee stdinin komennot ja suorittaa ne.
  3. Sammutus: Peruskomentojen suorittamisen jälkeen se suorittaa sammutuskomennot, vapauttaa muistia ja poistuu.

Näitä kolmea operaatiota käytämme komentokuljemme perustana. Emme lisää muita määritystiedostoja tai shutdown-komentoja. Kutsumme vain silmukkafunktiota ja viimeistelemme työn. On syytä huomata, että arkkitehtonisesta näkökulmasta elinkaari monimutkaisempi kuin pelkkä silmukka.

Int main(int argc, char **argv) ( // Lataa asetustiedostot, jos saatavilla. // Käynnistä komentosilmukka. lsh_loop(); // Sammuta / tyhjennä muisti. return EXIT_SUCCESS; )

Yllä olevassa esimerkissä näet lsh_loop()-funktion, joka kiertää komentoja. Tarkastellaan toteutusta alla.

Perus Shell Loop

Ensinnäkin meidän on mietittävä, miten ohjelman pitäisi toimia. Ja tässä on tärkeää ymmärtää, mitä kuori tekee silmukan aikana. Yksinkertainen tapa käsitellä komentoja koostuu kolmesta vaiheesta:

  1. Lue: Lue komento vakiovirroista.
  2. Jäsentäminen: ohjelman ja argumenttien tunnistaminen syötemerkkijonossa.
  3. Suorita: Suorita tunnistettu komento.

Tämä idea on toteutettu funktiossa lsh_loop():

Void lsh_loop(void) ( char *rivi; merkki **args; int status; do ( printf("> "); line = lsh_read_line(); args = lsh_split_line(line); status = lsh_execute(args); free(line) vapaa(args);

Käydään koodi läpi. Ensimmäiset rivit ovat vain ilmoituksia. Jälkiehtosilmukka on kätevämpi muuttujan tilan tarkistamiseen, koska se suoritetaan ennen sen arvon tarkistamista. Silmukan sisällä syöttökehote tulostetaan, funktioita kutsutaan lukemaan syötemerkkijono ja jakamaan merkkijono argumenteiksi, minkä jälkeen argumentit suoritetaan. Seuraavaksi merkkijonolle ja argumenteille varattu muisti vapautetaan. On syytä huomata, että koodi käyttää lsh_execute():n palauttamaa tilamuuttujaa määrittääkseen, milloin funktiosta poistutaan.

Rivin lukeminen

Merkkijonon lukeminen vakiosyötteestä näyttää yksinkertaiselta, mutta C:ssä se voi aiheuttaa paljon vaivaa. Ongelmana on, että kukaan ei tiedä etukäteen, kuinka paljon tekstiä käyttäjä kirjoittaa komentotulkkiin. Et voi vain korostaa lohkoa ja toivoa, että käyttäjät eivät ylitä sitä. Sen sijaan sinun on jaettava varattu muistilohko uudelleen, jos käyttäjät ylittävät sen rajat. Tämä on C:n vakioratkaisu, ja sitä käytetään lsh_read_line() -funktion toteuttamiseen.

#define LSH_RL_BUFSIZE 1024 char *lsh_read_line(void) ( int bufsize = LSH_RL_BUFSIZE; int position = 0; char *puskuri = malloc(sizeof(char) * bufsize); int c; if (!puskuri) ( fprintf(stderr, " : muistin varausvirhe\n"); exit(EXIT_FAILURE); ) while (1) ( // Lue merkki c = getchar(); // Kun kohtaat EOF:n, korvaa se nollapäätteellä ja palauta puskuri, jos (c == EOF ||. c == "\n") ( puskuri = "\0"; paluu puskuri; ) else ( puskuri = c; ) position++ // Jos ylitämme puskurin, varaa muistilohko uudelleen, jos (sijainti > = bufsize) ( bufsize += LSH_RL_BUFSIZE; puskuri = realloc(puskuri, bufsize); if (!puskuri) ( fprintf(stderr, "lsh: muistin varausvirhe\n"); exit(EXIT_FAILURE); ) ) )

Ensimmäisessä osassa on paljon ilmoituksia. On syytä huomata, että koodi käyttää vanhaa C-tyyliä muuttujien ilmoittamiseen ennen koodin runkoa. Pääosa funktiosta on näennäisen loputtoman while(1)-silmukan sisällä. Silmukassa merkki luetaan ja tallennetaan int-merkkinä eikä merkkinä (EOF on kokonaisluku, ei merkki, joten käytä int-merkkiä tarkistaaksesi). Jos se on rivinvaihto tai EOF, poistumme nykyinen linja ja palauta se. Muussa tapauksessa merkki lisätään olemassa olevaan merkkijonoon.

Tarkistamme sitten, onko seuraava merkki puskurin ulkopuolella. Jos näin on, jaamme puskurin uudelleen (tarkistaen samalla varausvirheiden varalta) ja jatkamme suorittamista.

C-standardin kirjaston uudempiin versioihin perehtyneet saattavat huomata, että stdio.h:ssä on getline()-funktio, joka tekee suurimman osan yllä olevassa koodissa toteutetusta työstä. Tämä ominaisuus oli GNU-laajennus C-kirjastoon vuoteen 2008 asti, minkä jälkeen se lisättiin spesifikaatioihin, joten useimmat nykyaikaiset Unix-järjestelmät tulevat sen mukana. Getlinella funktio muuttuu triviaaliksi:

Char *lsh_read_line(void) ( char *rivi = NULL; ssize_t bufsize = 0; // getline varaa muistin getline(&line, &bufsize, stdin); paluurivi; )

Jäsentää merkkijonoja

Nyt meidän on jäsennettävä syöttömerkkijono argumenttiluetteloksi. Teemme hieman yksinkertaistamista ja estämme käyttäjää käyttämästä lainausmerkkejä ja kenoviivaa komentorivin argumenteissa. Sen sijaan käytämme välilyöntejä argumenttien erottamiseen. Siten kaikukomento "tässä on viesti" ei kutsu kaikukomentoa yhdellä argumentilla "tässä on viesti", vaan kahdella: "täällä" ja "viesti".

Nyt meidän tarvitsee vain jakaa merkkijono osiin käyttämällä välilyöntejä erottimina. Tämä tarkoittaa, että voimme käyttää klassista kirjastofunktiota strtok.

#define LSH_TOK_BUFSIZE 64 #define LSH_TOK_DELIM "\t\r\n\a" char **lsh_split_line(char *line) ( int bufsize = LSH_TOK_BUFSIZE, sijainti = 0; merkki **tokens = malloc(bufsize*) * sizeof(char) char *tunniste tokens = token sijainti ++ \n"); exit(EXIT_FAILURE); ) ) token = strtok(NULL, LSH_TOK_DELIM); ) tokens = NULL; palauta tunnukset; )

Tämän funktion toteutus on epäilyttävän samanlainen kuin lsh_read_line() ja hyvästä syystä! Tässä käytetään samaa strategiaa, mutta nollapääteisen merkkijonon sijaan käytämme nollapääteistä osoitintaulukkoa.

Aloitamme osioinnin soittamalla strtokille. Se palauttaa osoittimen merkkijonon ensimmäiseen osaan (token). Yleensä strtok() palauttaa osoittimet merkkijonon paikkoihin ja sijoittaa tyhjät päätteet jokaisen merkin loppuun. Tallennamme nämä osoittimet erilliseen taulukkoon.

Tarvittaessa kohdistamme osoitintaulukon uudelleen. Toistamme prosessia, kunnes strtok lopettaa merkkien palauttamisen, ja päätämme merkkijonon nollapäätteellä.

Meillä on nyt joukko tokeneja valmiina suoritettaviksi.

Kuinka komentotulkit käynnistävät prosesseja

Nyt päästään sen ytimeen, mitä kuori tekee. Prosessien suorittaminen on komentotulkojen päätoiminto. Siksi, jos luot kuoren, sinun on tiedettävä tarkalleen, mitä prosesseille tapahtuu ja kuinka ne käynnistetään. Siksi puhumme nyt siitä.

Unixissa on vain kaksi tapaa ajaa prosesseja. Ensimmäinen (jota emme laske) on Init . Näet, kun Unix-järjestelmä käynnistyy, sen ydin ladataan. Käynnistyksen ja alustuksen jälkeen ydin käynnistää vain yhden prosessin, nimeltään Init. Tämä prosessi suoritetaan tietokoneen ollessa käynnissä ja hallitsee muiden sen toiminnan kannalta välttämättömien prosessien lataamista.

Koska kaikki muut prosessit eivät ole Init, niitä on jäljellä vain yksi käytännöllinen tapa prosessien käynnistäminen: fork()-järjestelmäkutsu. Kun tätä toimintoa kutsutaan, käyttöjärjestelmä tekee prosessista kaksoiskappaleen ja suorittaa ne rinnakkain. Alkuperäistä prosessia kutsutaan "vanhemmiksi" ja uutta prosessia kutsutaan "lapseksi". Fork() palauttaa 0:n aliprosessille ja palauttaa sen aliprosessin prosessitunnisteen (PID) vanhemmalle. Siten mikä tahansa uusi prosessi voidaan luoda vain kopiosta olemassa olevasta.

Tämä voi tuntua ongelmalta. Yleensä kun haluat aloittaa uuden prosessin, et halua kopiota jo käynnissä olevasta ohjelmasta, vaan haluat käynnistää toisen ohjelman. Tätä varten sinun on käytettävä exec()-järjestelmäkutsua. Se korvaa käynnissä olevan ohjelman kokonaan uudella. Tämä tarkoittaa, että kun exec kutsutaan, käyttöjärjestelmä pysäyttää prosessin, lataa uuden ohjelman ja käynnistää sen samasta paikasta. Exec()-kutsu ei palauta prosessia, ellei kyseessä ole virhe.

Nämä kaksi järjestelmäkutsua mahdollistavat useimpien ohjelmien suorittamisen Unixissa. Ensin olemassa oleva prosessi haarautuu vanhemmaksi ja lapseksi, ja sitten aliprosessi käyttää exec():tä korvatakseen itsensä uusi ohjelma. Pääprosessi voi jatkaa muiden asioiden tekemistä sekä pitää silmällä lapsiaan käyttämällä wait()-järjestelmäkutsua.

Kyllä, tietoa on paljon. Katsotaanpa ohjelman käynnistyskoodia:

Int lsh_launch(char **args) ( pid_t pid, wpid; int status; pid = fork(); if (pid == 0) ( // Lapsiprosessi if (execvp(args, args) == -1) ( virhe ("lsh" ) exit(EXIT_FAILURE) else if (pid)< 0) { // Ошибка при форкинге perror("lsh"); } else { // Родительский процесс do { wpid = waitpid(pid, &status, WUNTRACED); } while (!WIFEXITED(status) && !WIFSIGNALED(status)); } return 1; }

Tämä funktio ottaa luettelon aiemmin luomistamme argumenteista. Sitten se purkaa prosessin ja tallentaa palautusarvon. Kun fork() palauttaa, meillä on kaksi rinnakkaista prosessia. Lapsiprosessi vastaa ensimmäistä if-ehtoa (jossa pid == 0).

Lapsiprosessissa haluamme suorittaa käyttäjän määrittämän komennon. Siksi käytämme exec-järjestelmäkutsun muunnelmaa, execvp. Eri muunnelmia exec tekee eri asioita. Jotkut hyväksyvät vaihteleva määrä merkkijonoargumentteja, toiset ottavat luettelon merkkijonoista ja toiset sallivat sinun määrittää ympäristön, jossa prosessi suoritetaan. Tämä erityinen muunnelma ottaa ohjelman nimen ja taulukon (jota kutsutaan myös vektoriksi, joten "v") merkkijonoargumenteista (ensimmäisen on oltava ohjelman nimi). "p" tarkoittaa, että sen sijaan, että tarjoamme suoritettavan ohjelmatiedoston täyden polun, määritämme vain sen nimen ja kehotamme käyttöjärjestelmää etsimään sen itse.

Jos exec-komento palauttaa -1:n (tai minkä tahansa muun arvon), tapahtui virhe. Joten käytämme virheilmoitusta tulostamaan virheilmoituksen ohjelman nimen kanssa, jotta on selvää, missä virhe tapahtui. Sitten teemme prosessin loppuun, mutta niin kuori jatkoi työtä.

Toinen ehto (pid< 0) проверяет, произошла ли в процессе выполнения fork() ошибка. Если ошибка есть, мы выводим сообщение об этом на экран, но программа продолжает работать.

Kolmas ehto tarkoittaa, että fork()-kutsu on suoritettu onnistuneesti. Tämä on emoprosessin paikka. Tiedämme, että lapsi on suorittamassa prosessia, joten vanhemman on odotettava komennon valmistumista. Käytämme waitpid()-funktiota odottamaan prosessin tilan muuttumista. Valitettavasti waitpid() sisältää monia vaihtoehtoja (esimerkiksi exec()). Prosessit voivat muuttaa tilaansa monin tavoin, eivätkä kaikki tilat tarkoita prosessin päättymistä. Prosessi voi joko päättyä normaalisti (onnistuneesti tai virhekoodilla) tai pysäyttää signaalin. Joten käytämme waitpid():n tarjoamia makroja varmistaaksemme, että prosessi on valmis. Funktio palauttaa sitten 1:n signaalina kutsuvalle funktiolle, että se voi tulostaa kehotteen uudelleen.

Shell sisäänrakennettu

Olet ehkä huomannut, että lsh_loop()-funktio kutsuu lsh_execute() -funktiota, mutta yllä kutsuimme funktiota lsh_launch() . Tämä oli tahallista! Asia on siinä, että suurin osa komentotulkin suorittamista komennoista on ohjelmia - mutta eivät kaikki. Jotkut komennot on rakennettu suoraan kuoreen.

Syy on melko yksinkertainen. Jos haluat vaihtaa hakemistoa, sinun on käytettävä chdir()-funktiota. Tosiasia on, että nykyinen hakemisto on prosessin ominaisuus. Oletetaan siis, että kirjoitit cd-ohjelman, joka muuttaa hakemistoa. Se vain muuttaa nykyistä hakemistoaan ja poistuu, mutta pääprosessin nykyinen hakemisto ei muutu. Sen sijaan komentotulkkiprosessin on suoritettava chdir() päivittääkseen nykyisen hakemistonsa. Sitten kun se käynnistää lapsiprosessit, he myös perivät tämän hakemiston.

Samoin exit-niminen ohjelma ei pysty poistumaan sitä kutsuneesta komentokuljesta. Tämä komento tulee myös rakentaa komentotulkkiin. Lisäksi useimmat komentotulkit konfiguroidaan määrityskomentosarjoilla, kuten ~/.bashrc. Nämä komentosarjat käyttävät komentoja, jotka muuttavat komentotulkin toimintaa. Itse komennot voivat muuttaa tapaa, jolla kuori toimii, kunhan ne on toteutettu itse kuoressa.

Näin ollen on järkevää lisätä komentotulkkiin joitain komentoja. Tähän kuoreen lisäämme cd:n, exit ja help. Ja tässä on näiden toimintojen toteutus:

/* Sisäänrakennettujen komentotulkkien funktioiden ilmoittaminen: */ int lsh_cd(char **args); int lsh_help(char **args); int lsh_exit(char **args); /* Luettelo sisäänrakennetuista komennoista ja vastaavista funktioista */ char *builtin_str = ( "cd", "help", "exit" ); int (*builtin_func) (char **) = ( &lsh_cd, &lsh_help, &lsh_exit ); int lsh_num_builtins() ( return sizeof(builtin_str) / sizeof(char *); ) /* Sisäisten funktioiden toteutukset */ int lsh_cd(char **args) ( if (args == NULL) ( fprintf(stderr, " lsh: \"cd\"\n":n odotettu argumentti); ) else (if (chdir(args) != 0) ( perror("lsh"); ) ) return 1; ) int lsh_help(char **args) ( int i ; printf("LSH, Stephen Brennan\n"); printf("Kirjoita ohjelman nimi ja sen argumentit ja paina enter.\n"); printf("Tässä on luettelo sisäänrakennetuista komennoista: \n");< lsh_num_builtins(); i++) { printf(" %s\n", builtin_str[i]); } printf("Используйте команду man для получения информации по другим программам.\n"); return 1; } int lsh_exit(char **args) { return 0; }

Koodi koostuu kolmesta osasta. Ensimmäinen osa sisältää alustavat toimintomääritykset. Välitysilmoitus on, kun ilmoitat (mutta et määrittele) jotain niin, että nimeä voidaan käyttää ennen kuin se määritellään. lsh_help() on syy miksi teemme tämän. Se käyttää joukkoa sisäänrakennettuja toimintoja, ja itse taulukot sisältävät lsh_help() . Helpoin tapa katkaista tämä riippuvuuskierre on ennakkoilmoitus.

Seuraava osa on joukko sisäänrakennettuja komentojen nimiä, joita seuraa joukko vastaavia toimintoja. Tämä tarkoittaa, että tulevaisuudessa sisäänrakennettuja komentoja voidaan lisätä muokkaamalla näitä taulukoita sen sijaan, että jossain koodissa olisi suuri kytkinlause. Jos buildin_func-ilmoitus hämmentää sinua, se ei haittaa. Tämä on joukko funktioosoittimia (joka ottaa joukon merkkijonoja ja palauttaa int). Mikä tahansa ilmoitus, joka sisältää funktioosoittimia C:ssä, voi olla todella monimutkainen.

Lopuksi jokainen toiminto toteutetaan. Funktio lsh_cd() tarkistaa ensin toisen argumenttinsa olemassaolon ja tulostaa virheilmoituksen, jos sitä ei ole. Sitten se kutsuu chdir() , tarkistaa virheet ja poistuu. Ohjetoiminto näyttää informatiivisen viestin ja kaikkien sisäänrakennettujen toimintojen nimet. Ja poistumisfunktio palauttaa 0:n signaalina komentosilmukan lopettamiseksi.

Yhdistelee sisäänrakennettuja toimintoja ja prosesseja

Palapelin viimeinen puuttuva pala on lsh_execute()-funktion toteutus, joka joko käynnistää joko alkuperäisen tai muun prosessin.

Int lsh_execute(char **args) ( int i; if (args == NULL) ( // Tyhjä komento annettiin. return 1; ) for (i = 0; i< lsh_num_builtins(); i++) { if (strcmp(args, builtin_str[i]) == 0) { return (*builtin_func[i])(args); } } return lsh_launch(args); }

Koodi tarkistaa, onko komento rivissä. Jos näin on, se käynnistää sen, muuten kutsuu lsh_launch() käynnistääkseen prosessin.

Laittamalla kaikki yhteen

Se on kaikki koodi, joka menee komentotulkkiin. Jos luit artikkelin huolellisesti, sinun olisi pitänyt ymmärtää, kuinka kuori toimii. Jos haluat kokeilla komentotulkkia (Linuxissa), sinun on kopioitava nämä koodisegmentit main.c-tiedostoon ja käännettävä se. Muista sisällyttää vain yksi lsh_read_line()-toteutus. Sinun on sisällytettävä seuraavat otsikkotiedostot:

  • #sisältää
    • waitpid() ja siihen liittyvät makrot
  • #sisältää
    • chdir()
    • haarukka()
    • exec()
    • pid_t
  • #sisältää
    • malloc()
    • realloc()
    • vapaa()
    • exit()
    • execvp()
    • EXIT_SUCCESS, EXIT_FAILURE
  • #sisältää
    • fprintf()
    • printf()
    • stderr
    • getchar()
    • virhe ()
  • #sisältää
    • strcmp()
    • strtok()

Kääntääksesi tiedoston, kirjoita päätteeseen gcc -o main main.c ja sen jälkeen ./main.

Lisäksi kaikki lähteet ovat saatavilla GitHubissa.

Yhteenvetona

On selvää, että tämä kuori ei ole monikäyttöinen. Jotkut hänen puutteistaan:

  • argumentit erotetaan vain välilyönneillä, lainausmerkkejä tai kenoviivaa ei tueta;
  • ei uudelleenohjausta tai putkia;
  • muutamia sisäänrakennettuja toimintoja;
  • ei tiedostonimen vaihtoa.

Ymmärtää järjestelmäpuhelut, suosittelemme tutustumaan käsikirjaan: man 3p. Jos et tiedä mitä käyttöliittymää C- ja Unix-standardikirjastot tarjoavat sinulle, suosittelemme tutustumaan POSIX-määritykseen, erityisesti kohtaan 13.

Komentokielen kuori (käännettynä shelliksi, kuoreksi) on itse asiassa erittäin korkeatasoinen ohjelmointikieli. Tällä kielellä käyttäjä hallitsee tietokonetta. Yleensä sisäänkirjautumisen jälkeen alat olla vuorovaikutuksessa komentotulkin kanssa. Merkki siitä, että kuori on valmis vastaanottamaan komentoja, on kehote, jonka se näyttää näytöllä. Yksinkertaisimmassa tapauksessa se on yksi dollari ("$"). Shell ei ole välttämätön ja ainoa komentokieli (vaikka se onkin se joka on standardoitu POSIX-standardin sisällä mobiilijärjestelmät). Esimerkiksi cshell-kieli on melko suosittu, on myös kshell, bashell ja muut. Lisäksi jokainen käyttäjä voi luoda oman komentokielensä. Voi työskennellä samanaikaisesti eri komentokielien kanssa yhdessä käyttöjärjestelmän esiintymässä. shell on yksi monista UNIX-komennoista. Eli "shell"-komentosarja sisältää "sh"-komennon - kutsuen "shell"-tulkin. Ensimmäinen "shell" kutsutaan automaattisesti, kun kirjaudut sisään ja näyttää ohjelmoijan. Tämän jälkeen voit kutsua mitä tahansa komentoja suoritettaviksi, mukaan lukien "shell" itse, joka luo sinulle uuden kuoren vanhan sisään. Jos esimerkiksi valmistelet tiedoston "file_1" editorissa:

Echo Hei!

sitten se on normaalia tekstitiedosto, joka sisältää "echo"-komennon, joka suoritettuna näyttää kaiken sen oikealle puolelle kirjoitetun näytöllä. Voit tehdä tiedostosta "file_1" suoritettavan komennolla "chmod 755 file_1". Mutta se voidaan tehdä kutsumalla nimenomaisesti "sh" ("shell") -komento:

Sh-tiedosto_1

Sh< file1

Tiedosto voidaan suorittaa myös nykyisessä shell-instanssissa. Tälle "":lle on erityinen komento. (piste), ts.

Tiedosto_1

Koska UNIX on monen käyttäjän järjestelmä, voit jopa työskennellä henkilökohtaisella tietokoneella rinnakkain esimerkiksi 12 näytöllä (vaihda näytöstä toiseen ALT/toimintonäppäin), jolloin jokaisella näytöllä on uusi (tai sama) käyttäjä, jolla on oma komentokuorinsa. Voit myös graafinen tila Myös X-ikkuna auki iso luku windows, ja jokaisella ikkunalla voi olla oma käyttäjä, jolla on oma komentotulkki... Shell-kielen ydinelementti on komento.

Komentorakenteet:

Komentotulkin komennot ovat yleensä seuraavassa muodossa:

<имя команды> <флаги> <аргумент(ы)>

Esimerkiksi:

Ls -ls /usr/bin

Missä ls on hakemiston sisällön tulostavan komennon nimi, -ls on liput ("-" on lippujen merkki, l on pitkä muoto, s on tiedostojen määrä lohkoissa), /usr/ bin on hakemisto, jolle komento suoritetaan. Tämä komento näyttää /usr/bin-hakemiston sisällön pitkässä muodossa ja lisää tietoja kunkin tiedoston koosta. Valitettavasti tätä komentorakennetta ei aina noudateta miinusmerkillä, ja liput eivät ole aina yhtä sanaa argumenttien esittämisessä. Eksoottisten muotojen komennot sisältävät sellaiset "ajo-komennot" kuin cc - C-kääntäjän kutsuminen, tar - arkistointi, dd - kopiointi. tiedosto muuntamalla, etsi - tiedostojen etsiminen ja joukko muita Yleensä kuori havaitsee ensimmäisen sanan komennona. komentorivi

komentotulkki purkaa ensimmäisen sanan komennona (ketjutus), joka näyttää tiedoston nimeltä "cat" (toinen sana), joka sijaitsee nykyisessä hakemistossa. Komennon uudelleenohjaus Vakiosyöttö (input) - "stdin" UNIX-käyttöjärjestelmässä suoritetaan päätteen näppäimistöltä, ja vakiolähtö (lähtö) - "stdout" ohjataan päätteen näytölle. On myös vakiotiedosto diagnostiset viestit - "stderr", joista keskustellaan hieman myöhemmin. Komentoa, joka voi toimia vakiotulolla ja -lähdöllä, kutsutaan FILTERiksi. Käyttäjällä on kätevät keinot tulon ja lähdön uudelleenohjaus muihin tiedostoihin (laitteisiin). Symbolit ">" ja ">> osoittavat lähdön uudelleenohjausta. ls >file_1 Komento "ls" luo luettelon nykyisen hakemiston tiedostoista ja sijoittaa sen tiedostoon "file_1" (sen sijaan, että se tulostaisi sen näytölle). Jos tiedosto "file_1" oli olemassa aiemmin, uusi korvaa sen.

Pwd >> tiedosto_1

pwd joukkue muodostuu koko nimi nykyiseen hakemistoon ja sijoittaa sen tiedoston "file_1" loppuun, ts. ">>" liittää tiedostoon, jos se ei ole tyhjä. Symbolit "<" и "<<" обозначают перенаправление ввода.

wc -l

laskee ja näyttää rivien määrän tiedostossa file_1.

Ed tiedosto_2<

luo tiedoston "file_2" editorilla suoraan päätteestä. Syötteen lopun määrää oikealla oleva merkki "<<" (т. е. "!"). То есть ввод будет закончен, когда первым в очередной строке будет "!". Можно сочетать перенаправления. Так

wc -l tiedosto_4

Wc -l >tiedosto_4

suoritetaan samalla tavalla: tiedoston "file_3" rivien määrä lasketaan ja tulos sijoitetaan tiedostoon "file_4". Välineitä, jotka yhdistävät yhden komennon vakiolähdön toisen komennon vakiotuloon, kutsutaan PIPELINE:ksi ja se osoitetaan pystypalkilla "|".

ls | wc -l

luettelo nykyisen hakemiston tiedostoista lähetetään "wc"-komennon syötteeseen, joka näyttää hakemiston rivien määrän. Liukuhihna voi myös yhdistää enemmän kuin kaksi komentoa, kun ne kaikki, mahdollisesti ensimmäistä ja viimeistä lukuun ottamatta, ovat suodattimia:

Kissatiedosto_1 | grep -h tulos | lajitella | kissa -b > tiedosto_2

Tämä liukuhihna tiedostosta "file_1" ("cat") valitsee kaikki rivit, jotka sisältävät sanan "result" ("grep"), lajittelee ("sort") tuloksena olevat rivit ja sitten numeroi ("cat -b") ja tulosta tulos tiedostoon "file_2". Koska UNIX-laitteita edustavat erityiset tiedostot, niitä voidaan käyttää uudelleenohjauksissa. Erikoistiedostot sijaitsevat "/dev"-hakemistossa. Esimerkiksi "lp" - tulosta; "konsoli" - konsoli; "ttyi" - i:s pääte; "null" on vale (tyhjä) tiedosto (laite). Sitten esim.

Ls > /dev/lp

tulostaa nykyisen hakemiston sisällön ja tiedoston_1< /dev/null обнулит файл "file_1".

Lajittele tiedosto_1 | tee /dev/lp | häntä -20

Tässä tapauksessa tiedosto "file_1" lajitellaan ja tulostetaan, ja myös viimeiset 20 riviä tulostetaan näytölle. Palataan tulosten uudelleenohjaukseen. Vakiotiedostot on numeroitu:

0 - stdin, 1 - stdout 2 - stderr. Jos et halua virheilmoitusta näytöllä, voit ohjata sen näytöltä määrittämääsi tiedostoon (tai heittää sen kokonaan pois ohjaamalla sen tyhjään laitetiedostoon - /dev/null). Esimerkiksi komentoa suoritettaessa

Kissatiedosto_1 tiedosto_2

jonka pitäisi näyttää tiedostojen "file_1" ja "file_2" sisällöt peräkkäin näytöllä, se antaa sinulle esimerkiksi seuraavan

111111 222222 cat: f2: Ei tällaista tiedostoa tai hakemistoa

jossa 111111 222222 on tiedoston "file_1" sisältö ja tiedosto "file_2" puuttuu, jonka "cat"-komento raportoi vakiodiagnostiikkatiedostoon oletusarvoisesti, samoin kuin näytön edustama vakiotulostus. Jos et halua tällaista viestiä näytölle, voit ohjata sen uudelleen määrittämääsi tiedostoon:

Kissatiedosto_1 tiedosto_2 2>f-err

virheilmoitukset lähetetään (kuten "2>"-uudelleenohjaus osoittaa) "f-err"-tiedostoon. Muuten, voit lähettää kaikki tiedot yhteen tiedostoon "ff" käyttämällä tässä tapauksessa rakennetta

Kissatiedosto_1 tiedosto_2 >>ff 2>ff

Voit määrittää uudelleenohjattavan vakiotiedoston lisäksi myös sen, mihin vakiotiedostoon uudelleenohjataan.

Kissatiedosto_1 tiedosto_2 2>>ff 1>&2

Tässä ensin "stderr" uudelleenohjataan (lisäystilassa) tiedostoon "ff" ja sitten vakiotulostus uudelleenohjataan "stderriin", joka tässä vaiheessa on tiedosto "ff". Eli tulos on samanlainen kuin edellinen. Rakenne "1>&2" tarkoittaa, että normaalin uudelleenohjattavan tiedoston numeron lisäksi sinun tulee laittaa "&" eteen; koko rakenne on kirjoitettu ilman välilyöntejä.<- закрывает стандартный ввод. >- sulkee vakiolähdön. Komentotiedostot. On olemassa useita vaihtoehtoja, joiden avulla tekstitiedostoa voidaan käyttää komentona. Luodaan editorilla tiedosto nimeltä "cmd", joka sisältää yhden rivin seuraavasti:

Päivämäärä; pwd; ls

Voit kutsua komentotulkkia komennona, jonka nimi on "sh", ja välittää sille "cmd"-tiedoston argumenttina tai uudelleenohjatuksi syötteenä, ts.

$ sh cmd

$sh

Näiden komentojen suorittamisen tulos on päivämäärä, sitten nykyisen hakemiston nimi ja sitten hakemiston sisältö. Mielenkiintoisempi ja kätevämpi tapa työskennellä erätiedoston kanssa on muuttaa se suoritettavaksi, ts. tee siitä komento, joka saavutetaan muuttamalla suojakoodia. Tätä varten sinun on sallittava tämän tiedoston suorittaminen. Esimerkiksi,

Chmod 711 cmd

tekee suojakoodin "rwx__x__x". Sitten yksinkertainen puhelu

suorittaa samat kolme komentoa. Tulos on sama, jos tiedosto sisältää sisällön

Päivämäärä; pwd; ls

on esitetty muodossa: date pwd ls, koska siirtyminen toiselle riville on myös erotin komentojonossa. Suoritettavat tiedostot voivat siis olla paitsi kääntämisen ja kokoonpanon tuloksena saatuja tiedostoja, myös shell-kielellä kirjoitettuja tiedostoja. Ne suoritetaan tulkintatilassa käyttämällä shell-tulkkia

Erätiedostojen virheenkorjaus

SHELL käyttää kahta mekanismia erätiedostojen virheenkorjaukseen. Ensimmäinen on: set -v tulostaa rivit erätiedosto kun luet niitä. Tätä tilaa käytetään syntaksivirheiden etsimiseen. Käyttääksesi sitä, sinun ei tarvitse muokata komentotiedostoa, esimerkiksi: sh -v proc... tässä proc on komentotiedoston nimi. -v-kytkintä voidaan käyttää yhdessä -n-kytkimen kanssa, mikä estää seuraavien komentojen suorittamisen (komento set -n estää päätteen, kunnes EOF-lippu syötetään). Set -x -komento näyttää komennot sitä mukaa, kun niitä suoritetaan, ja ohjelmarivit tulostetaan päätteelle ja niiden arvot korvataan muuttujien tilalla. Voit peruuttaa kytkimien -x ja -v käyttämällä set-komentoa - ja asentaaksesi määrittämällä vastaavan arvon makromuuttujalle. SHELL-YMPÄRISTÖ (MUUTTUJAT JA PARAMETRIT) Shell-kielellä voit kirjoittaa erätiedostoja ja tehdä niistä suoritettavia komennolla "chmod". Tämän jälkeen ne eivät eroa muista UNIX-käyttöjärjestelmän komennoista.

Shell-muuttujat

Kuorimuuttujan nimi on sarja kirjaimia, numeroita ja alaviivoja, jotka alkavat kirjaimella. Shell-muuttujan arvo on merkkijono. Se, että kuoressa on vain kahden tyyppistä dataa: merkkijono ja tekstitiedosto, helpottaa ohjelmointiin osallistumista loppukäyttäjiä, jotka eivät ole koskaan aiemmin ohjelmoineet, ja toisaalta, aiheuttaa tietyn sisäisen vastalauseen monien ohjelmoijien keskuudessa, jotka ovat tottuneet huomattavasti suurempaan monimuotoisuuteen ja kielellisten keinojen joustavuuteen. On kuitenkin mielenkiintoista seurata, kuinka korkeasti koulutetut ohjelmoijat, jotka ovat perehtyneet kuoren "pelin sääntöihin", kirjoittavat siihen ohjelmia monta kertaa nopeammin kuin C:ssä, mutta mikä on erityisen mielenkiintoista, joissain tapauksissa nämä ohjelmat toimivat jopa nopeammin kuin C:ssä toteutetut. Muuttujan nimi on samanlainen kuin perinteinen käsite tunnisteesta, ts. nimi voi olla sarja kirjaimia, numeroita ja alaviivoja, jotka alkavat kirjaimella tai alaviivalla. Määritysoperaattoria "=" voidaan käyttää arvojen määrittämiseen muuttujille.

Muutt_1=13 - "13" ei ole numero, vaan kahdesta numerosta koostuva merkkijono. var_2="UNIX OS" - Tässä vaaditaan lainausmerkkejä (" "), koska merkkijonossa on välilyönti.

Myös muut tavat määrittää arvoja kuorimuuttujille ovat mahdollisia. Esimerkiksi äänitys

DAT = "päivämäärä".

aiheuttaa sen, että "date"-komento suoritetaan ensin (backtick-merkit osoittavat, että suljettu komento on suoritettava ensin), ja sen suorituksen tulos sen sijaan, että se tulostettaisiin vakiolähtöön, määritetään muuttujan arvoksi, tässä tapauksessa "DAT". Voit myös määrittää muuttujalle arvon "read"-komennolla, joka varmistaa, että muuttujan arvo saadaan (näppäimistö) näytöltä dialogitilassa. Yleensä erätiedoston "read"-komentoa edeltää "echo"-komento, jonka avulla voit esitellä jonkin viestin näytöllä. Esimerkiksi:

Echo -n "Syötä kolminumeroinen luku:" lue x

Kun suoritetaan tämä komentotiedoston osa, sen jälkeen, kun sanoma on näytetty

Syötä kolminumeroinen luku:

tulkki pysähtyy ja odottaa, että arvo syötetään näppäimistöltä. Jos syötit esimerkiksi "753", tästä tulee muuttujan "x" arvo. Yksi "lue"-komento voi lukea (määrittää) arvoja useille muuttujille kerralla. Jos "read"-kohdassa on enemmän muuttujia kuin syötetään (välilyönnillä erotettuina), jäljelle jääville annetaan tyhjä merkkijono. Jos "read"-komennossa on lähetettyjä arvoja enemmän kuin muuttujia, ylimääräiset ohitetaan. Kun käytät komentotulkkimuuttujaa, sinun on ennen nimeä oltava "$"-symboli. Joten komennot echo $var_2 echo var_2 näkyvät näytöllä

UNIX OS var_2 Escaping

Katsotaanpa tarkemmin kuoressa käytettyjä pakotekniikoita. Kaksoislainausmerkkejä (" "), lainausmerkkejä (" ") ja kenoviivaa (\) käytetään poistovälineinä. Heidän toimintansa käy ilmi esimerkeistä: Voit kirjoittaa useita tehtäviä yhdelle riville.

X=22 y=33 z=$x A="$x" B="$x" C=\$x D="$x + $y + $z" E="$x + $y + $z " F=$x\ +\ $y\ +\ $z

(tehtävä G=$x+$y epäonnistuisi välilyöntien takia) Sitten

Kaiku A = $A B = $B C = $C kaiku D = $D E = $E F = $F eval kaiku arvioitu A = $A eval kaiku arvioitu B = $B eval kaiku arvioitu C = $C

Näytetään näytöllä

A = 22 B = $x C = $x D = 22 + 33 + 22 E = $x + $y + $z F = 22 + 33 + 22 arvioitu A = 22 arvioitu B = 22 arvioitu C = 22

Annamme lisää esimerkkejä, jotka liittyvät rivinsyötteiden poistoon. Määritetään muuttujalle "string" 2x3 "taulukon" arvo: abc def Huomaa, että ylimääräisten välilyöntien määrittämisen välttämiseksi taulukon toinen rivi alkaa seuraavan rivin ensimmäisestä paikasta: string="abc def" Sitten on kolme vaihtoehtoa muuttujan kirjoittamiseen "echo" echo-komennossa $string echo "$string" echo "$string" antaa vastaavasti kolme erilaista tulosta: abc def $string abc def ja komentosarja echo "str_1 str_2" > file_1 echo "str_1 str_2" > file_2 cat file_1 file_2 antaa peräkkäin identtiset tiedostot file_1 ja file_2: str_1 str_2 str_1 str_2 Huomaa myös, että kenoviiva (\) ei vain ohita sitä seuraavaa merkkiä, jolloin voit käyttää erikoismerkkejä yksinkertaisesti itseään edustavina merkeinä (se voi myös välttää itsensä - \\), mutta komentotiedosto, kenoviiva mahdollistaa rivien ketjuttamisen yhdeksi (rivin lopun poisto esim. aiemmin annettu komentorivi).

Kissatiedosto_1 | grep -h tulos | lajitella | kissa -b > tiedosto_2

voidaan kirjoittaa erätiedostoon, sano kuten

Kissatiedosto_1 | grep -h\tulos | lajitella | kissa -b > tiedosto_2

Muuten, kuljetinsymboli toimii myös komentorivin jatkamisena. Tässä tapauksessa se voi antaa mukavamman tuloksen, kuten tämä:

Kissatiedosto_1 | grep -h tulos | lajitella | kissa -b > tiedosto_2

Manipulaatiot komentotulkkimuuttujilla Huolimatta siitä, että komentotulkkimuuttujat nähdään yleensä merkkijonoina, eli "35" ei ole numero, vaan kahden merkin "3" ja "5" merkkijono, ne voidaan joissain tapauksissa tulkita eri tavalla, esimerkiksi kokonaislukuina. "Expr"-komennolla on useita ominaisuuksia. Havainnollistetaan joitain esimerkein: Erätiedoston suorittaminen:

X=7 y=2 a=`laus $x + $y` ; echo a=$a a=`laus $a + 1` ; echo a=$a b=`lause $y - $x` ; echo b=$b c=`lause $x "*" $y` ; echo c=$c d=`lause $x / $y` ; kaiku d=$d e=`laus $x % $y` ; echo e=$e

tulee näkyviin näytölle

A = 9 a = 10 b = -5 c = 14 d = 3 e = 1

Kertolasku ("*") on pakottava, koska kuoressa tämä kuvake havaitaan erikoismerkiksi, mikä tarkoittaa, että mikä tahansa merkkijono voidaan korvata tässä paikassa. "Expr"-komennolla ei ole mahdollista vain (kokonaisluku)aritmeettisia operaatioita, vaan myös merkkijonoja:

A=`expr "cocktail" : "kukko"` ; echo $A B=`expr "cocktail" : "häntä"` ; echo $B C=`expr "cocktail" : "keittää"` ; echo $C D=`expr "kukko" : "cocktail"` ; kaiku $D

Numerot näkyvät näytöllä ja osoittavat vastaavien merkkien lukumäärän ketjuissa (alusta). Toinen rivi ei voi olla pidempi kuin ensimmäinen:

4 0 0 0

Muuttujien vienti UNIX-käyttöjärjestelmässä on prosessin käsite. Prosessi tapahtuu, kun komento suoritetaan. Esimerkiksi kun kirjoitat "p" näppäimistöllä "prosessi "p" syntyy. "p" puolestaan ​​voi synnyttää muita prosesseja. Oletetaan, että "p" kutsuu "p1" ja "p2", jotka peräkkäin synnyttävät vastaavat prosessit. Jokaisella prosessilla on oma ympäristönsä - a sen käytettävissä olevat muuttujat Esimerkiksi ennen "p":n käynnistämistä oli jo olemassa ympäristö, jossa "p":n käynnistäminen luo uuden ympäristön "p1":n ja "p2":n. Muuttujat ovat paikallisia siinä prosessissa, jossa ne on määritetty, jotta ne olisivat muiden syntyneiden prosessien käytettävissä, sisäänrakennettu "vienti"-komento on välitettävä käytetty.

Vaihtoehdot

Parametrit voidaan siirtää komentotiedostoon. Kuori käyttää sijaintiparametreja (eli niiden esiintymisjärjestys on tärkeä). Komentotiedostossa parametreja vastaavat muuttujat (samanlaiset kuin shell-muuttujat) alkavat symbolilla "$", jota seuraa yksi numeroista 0 - 9: Kutsutaan "examp-1" parametreillä "kuko" ja "häntä". Nämä parametrit kuuluvat uuteen ympäristöön vakionimet"1" ja "2". (Vakio)muuttuja nimeltä "0" tallentaa kutsutun laskutoimituksen nimen. Parametreja käytettäessä numeroa edeltää dollarimerkki "$" (kuten muuttujia käytettäessä): $0 vastaa tämän komentotiedoston nimeä; $1 on ensimmäinen parametri järjestyksessä; $2 sekunnin parametri jne. Koska muuttujien määrä, joille parametreja voidaan välittää, on rajoitettu yhteen numeroon, ts. 9. ("0", kuten jo todettiin, on erityinen merkitys), sitten suuremman määrän parametrien siirtämiseen käytetään erityistä "shift"-komentoa. "Set"-komento tarjoaa ainutlaatuisen lähestymistavan parametreihin. Esimerkiksi fragmentti

Aseta a b echo first=$1 second=$2 third=$3

tulee näkyviin näytölle

Ensimmäinen=a toinen=b kolmas=c

nuo. "set"-komento asettaa parametriarvot. Tämä voi olla erittäin kätevää. Esimerkiksi "date"-komento tulee näkyviin nykyinen päivämäärä, sano "Mon May 01 12:15:10 2000", joka koostuu viidestä sanasta, sitten

Aseta päivämäärä echo $1 $3 $5

tulee näkyviin näytölle

Ma 01 2000

"Set"-komennolla voit myös ohjata ohjelman suoritusta, esimerkiksi: set -v rivit tulostetaan terminaaliin, ja komentotulkki lukee. set +v peruuttaa edellisen tilan. set -x tulostaa komennot päätteelle ennen suorittamista. set +x peruuttaa edellisen tilan. "Set"-komento ilman parametreja näyttää ohjelmistoympäristön tilan päätelaitteelle.

Shellin vaihdot

Ennen komentotiedostojen sisältämien komentojen suoraa tulkintaa ja suorittamista komentotulkki suorittaa erilaisia ​​korvauksia: 1. TULOSTEN KORVAAMINEN. Kaikki lainausmerkkien sisällä olevat komennot suoritetaan ja tulos korvataan niiden tilalla. 2. PARAMETRIEN JA MUUTTUJIEN ARVOJEN KORVAAMINEN. Eli sanalla "$" alkavat sanat korvataan vastaavilla muuttujien ja parametrien arvoilla. 3. AUKOJEN TULKINTA. Poistetut välilyönnit jätetään huomiotta. 4. TIEDOSTOJEN NIMEN LUOMINEN. Sanoista tarkistetaan erikoismerkkejä ("*", "?","") ja vastaavat sukupolvet suoritetaan. Ohjelmistoympäristö Jokaisella prosessilla on ympäristö, jossa se toimii. Shell käyttää useita näistä ympäristömuuttujista. Jos kirjoitat "set"-komennon ilman parametreja, näytössä näkyy tietoja useista vakiomuuttujista, jotka on luotu kirjautumisen yhteydessä (ja sitten siirretty kaikille uusille prosesseillesi "peritty"), sekä prosessiesi luomista ja viemistä muuttujista. . Tietyn tiedon tyyppi ja sisältö riippuu suurelta osin siitä, mitä UNIX-versiota käytetään ja kuinka järjestelmä on asennettu.

Tulos set-komennon suorittamisesta ilman parametreja (ei valmis):

HOME=/root PATH=/usr/local/bin:/usr/bin:/bin:.:/usr/bin/X11: IFS= LOGNAME=sae MAIL=/var/spool/mail/sae PWD=/home/ sae/STUDY/SHELL PS1=$(PWD):" " PS2=> SHELL=/bin/bash

Kommentoidaan muuttujien arvoja. HOME=/root on sen kotihakemiston nimi, johon käyttäjä päätyy sisäänkirjautumisen jälkeen. Toisin sanoen, kun olen syöttänyt nimen ja salasanan oikein, löydän itseni "/root" -hakemistosta. PATH=/bin:/usr/bin:.:/usr/local/bin:/usr/bin/X11 - tämä muuttuja määrittää tiedostojen sarjan, jota komentotulkki etsii komentoa etsiessään. Tiedostojen nimet on erotettu tässä kaksoispisteillä. Katselujärjestys vastaa polun nimien järjestystä. Mutta aluksi haku tapahtuu niin kutsuttujen sisäänrakennettujen komentojen joukossa. Sisäänrakennetut komennot sisältävät yleisimmin käytetyt komennot, kuten "echo", "cd", "pwd", "date". Tämän jälkeen järjestelmä hakee läpi “/bin”-hakemiston, joka voi sisältää komennot “sh”, “cp”, “mv”, “ls” jne. Sitten hakemisto "/usr/bin" komennoilla "cat", "ss", "expr", "nroff", "man" ja monet muut. Seuraavaksi haku suoritetaan nykyisessä hakemistossa (.), tai muussa merkinnässä "tyhjä", eli ""), jossa kirjoittamasi komennot todennäköisimmin sijaitsevat. Kun olet kirjoittanut komentorivin ja painanut "shell" (suoritettuaan tarvittavat korvaukset) tunnistaa komentoa vastaavan nimen ja etsii sitä PATH:ssa luetelluista hakemistoista. Jos komento sijoitetaan näiden hakemistojen ulkopuolelle, sitä ei löydy. Jos useita samannimisiä komentoja kutsutaan ensin katsotussa hakemistossa olevaa komentoa. PATH, kuten muutkin muuttujat, voidaan helposti muuttaa lisäämällä, järjestämällä uudelleen tai poistamalla hakemistoja. IFS= (Internal Field Separator) luettelee merkit, jotka erottavat sanat (kentät). Nämä ovat "välilyönti", "sarkain" ja "rivinvaihto", joten tässä tehtävän vasemmalla puolella ei näy mitään ja kaksi riviä on varattu. LOGNAME=root - kirjautumisnimi ("käyttäjänimi"). MAIL=/var/spool/mail/root - sen tiedoston nimi, johon (sähköposti) vastaanotetaan. PWD=/root - nykyisen hakemiston nimi PS1=$(PWD):" " - hakemiston tyyppi. Tässä tapauksessa kehote näyttää nykyisen hakemiston nimen, jota seuraa kaksoispiste ja välilyönti. Eli siellä tulee olemaan "/root:". PS2=> - tätä kehotetta (tässä ">") käytetään kutsuna jatkaa keskeneräisen komennon kirjoittamista (seuraavalle riville). Kirjoita esimerkiksi aloitussulku "(" ja paina sen jälkeen V seuraava rivi näet tämän kehotteen. Jos et tiedä mitä tehdä seuraavaksi, kirjoita sulkeva hakasulku ")" ja se katoaa. SHELL=/bin/sh - Tämä muuttuja määrittää käyttäjän käyttämän kuoren. Tässä tapauksessa käytetään vakiokuorta ("sh"). Alkuperäinen ympäristö asennetaan automaattisesti sisäänkirjautumisen yhteydessä käyttämällä tiedostoja, kuten "/etc/rc" ja "/etc/.profile". Yksi tapa yksinkertaisesti muuttaa ympäristöä (esimerkiksi komennon hakupolku, ohjelmatyyppi, komentotulkkityyppi, näytön väri jne.) on sijoittaa nämä tiedot kotihakemistoosi erityiseen ".profile"-tiedostoon ($(HOME)/ profiili), määrittämällä vaaditut arvot ympäristömuuttujat. Eli kutsu tämä tiedosto editoriin ja kirjoita mitä haluat). Sitten joka kerta kun kirjaudut sisään, tämä tiedosto suoritetaan automaattisesti ja asennetaan uusi ympäristö. Tämä tiedosto TÄYTYY sijoittaa HOME-hakemistoosi (kirjautumishakemistoon). On syytä muistaa, että pisteellä alkavilla tiedostonimillä on yleensä erityinen tila. Siksi niitä ei näytetä näytöllä yksinkertaisella "ls"-komennolla - sinun on kutsuttava tämä komento "-a"-lipulla. Muuten, niitä ei tuhota umpimähkäisesti "rm *" -komennolla. Shell-tulkki itse määrittää automaattisesti arvot seuraaville muuttujille (parametreille): ? viimeisen komennon palauttama arvo; $ prosessin numero; ! taustaprosessin numero;

  1. kuoreen välitettyjen sijaintiparametrien lukumäärä;
  • parametrien luettelo yhtenä rivinä;

@ parametrien luettelo sanajoukona; - liput siirtyivät kuoreen. Kun käytät näitä muuttujia (eli kun käytät niitä komentotiedostossa - shell-ohjelmassa), sinun tulee laittaa "$" eteen. Tärkeä rooli yksilöllisten tiedostojen luomisessa on erikoismuuttujalla "$$", jonka arvo vastaa tämän laskennan suorittavan prosessin numeroa. Jokainen tietokoneen suorittama uusi laskenta käynnistää yhden tai useamman prosessin, joka vastaanottaa numerot automaattisesti järjestyksessä. Siksi käyttämällä prosessinumeroa tiedostonimenä voit olla varma, että jokaisella uudella tiedostolla on uusi nimi (ei kirjoiteta olemassa olevan nimen tilalle). Tämän tiedostojen nimeämismenetelmän etu on myös suurin haitta. Ei tiedetä, mitkä nimet tiedostoille annetaan. Ja jos tämän prosessin puitteissa löydät tiedoston "näkemättä", eli pääset siihen käyttämällä $$, niin tällaiset tiedostot voidaan helposti kadota. Tämä aiheuttaa lisäongelmia ohjelmien virheenkorjauksessa. Tulkin kutsuminen Kun käyttäjä on rekisteröity järjestelmään (käyttäen login-komentoa), kutsutaan SHELL-kielen tulkki. Jos käyttäjän rekisteröintihakemisto sisältää .profile-tiedoston, tulkki suorittaa tämän tiedoston ennen kuin vähintään yksi komento vastaanotetaan päätteeltä (oletetaan, että .profile-tiedosto sisältää komentoja). Kutsuttaessa voidaan määrittää seuraavat näppäimet: -c string Komennot luetaan annetusta merkkijonosta. -s Komennot luetaan vakiosyötteestä. Tulkkiviestit kirjoitetaan. -i Interaktiivinen käyttötila. Jos parametrin "0" ensimmäinen merkki on -merkki, komennot luetaan .profile-tiedostosta.

OHJELMAN RAKENTEET===

Kuten millä tahansa ohjelmointikielellä, shell-teksti voi sisältää kommentteja. "#"-symbolia käytetään tähän. Kaikki, mikä on rivillä (komentotiedostossa) tämän merkin vasemmalla puolella, tulkki havaitsee kommentiksi. Esimerkiksi,

# Tämä on kommentti.

Kuten kaikilla proseduuriohjelmointikielellä, kuorikielellä on operaattoreita. Useiden operaattoreiden avulla voit hallita komennon suoritusjärjestystä. Tällaisissa operaattoreissa on usein tarpeen tarkistaa kunto, joka määrittää suunnan, johon laskelmat jatkuvat.

Testaa ("") -komento

Testikomento tarkistaa, että tietty ehto täyttyy. Shell-kielen valinta- ja silmukkakäskyt luodaan tällä (sisäänrakennetulla) komennolla. Kaksi mahdollista komentomuotoa:

Testi kunto

[ehto]

käytämme toista vaihtoehtoa, ts. Sen sijaan, että kirjoittaisit sanan "testi" ennen ehtoa, kirjoitamme ehdon sulkeisiin, mikä on yleisempää ohjelmoijille. Itse asiassa komentotulkki tunnistaa tämän komennon aloitussulussa "[" sanaksi, joka vastaa "test"-komentoa. Sulujen ja niiden sisältämien ehtojen välillä on oltava välilyöntejä. Arvojen ja vertailu- tai toimintasymbolin välissä tulee olla myös välilyöntejä. Kuori käyttää eri "tyyppisiä" ehtoja. TIEDOSTOJEN TARKISTUKSEN EHDOT: -f tiedosto tiedosto "file" on tavallinen tiedosto; -d tiedosto tiedosto "tiedosto" - hakemisto; -с tiedosto tiedosto "tiedosto" on erityinen tiedosto; -r tiedostolla on oikeus lukea tiedosto "file"; -w tiedostolla on oikeus kirjoittaa tiedostoon "tiedosto"; -s-tiedosto tiedosto "file" ei ole tyhjä.

JOHTOJEN TESTAUKSEN EHDOT: str1 = str2 merkkijonot "str1" ja "str2" täsmäävät; str1 != str2-merkkijonot "str1" ja "str2" eivät ole samoja; -n str1 merkkijono "str1" on olemassa (ei tyhjä); -z str1 merkkijonoa "str1" ei ole olemassa (tyhjä). Esimerkkejä.

X="kuka on kuka"; vienti x; [ "kuka on kuka" = "$x" ]; kaiku $? 0 x = abc ; vienti x ; [ abc = "$x" ] ; kaiku $? 0 x = abc ; vienti x ; [ -n "$x" ] ; kaiku $? 0 x="" ; vienti x ; [ -n "$x" ] ; kaiku $? 1

Lisäksi niitä on kaksi vakioarvot ehdot, joita voidaan käyttää ehdon sijasta (tähän ei tarvita sulkeita). EHDOT KOKONAISLUKUJA VERTAILLE: x -eq y "x" on yhtä suuri kuin "y", x -ne y "x" ei ole yhtä suuri kuin "y", x -gt y "x" on suurempi kuin "y", x - ge y "x" on suurempi tai yhtä suuri kuin "y", x -lt y "x" pienempi kuin "y", x -le y "x" pienempi tai yhtä suuri kuin "y". MONIMUTTAISET EHDOT: Toteutettu käyttämällä tavallisia loogisia operaatioita: ! (not) kääntää poistumiskoodin arvon. -o (tai) vastaa loogista "OR". -a (ja) vastaa loogista "AND".

Ehdollinen lause "jos"

Yleensä "if"-lauseella on rakenne

Jos kunto niin lista

Täällä "elif" voidaan käyttää lyhennettyä versiota "else if" -sanasta täyden version kanssa, ts. mielivaltaisen määrän "if"-lauseita (sekä muita lausekkeita) sisäkkäin on sallittu. Tietenkin "luettelon" on kussakin tapauksessa oltava merkityksellinen ja hyväksyttävä annetussa kontekstissa. Tämän operaattorin katkaistuin rakenne

Jos kunto niin lista fi

jos ehto täyttyy (yleensä tämä on paikka, jossa täydennyskoodi "0" vastaanotetaan), "lista" suoritetaan, muuten se ohitetaan Esimerkkejä: kirjoitetaan "jos-1".

Jos [ $1 -gt $2 ]

sitten pwd else echo $0: Hei!

Sitten soittaminen numeroon if-1 12 11 tuottaa /home/sae/STUDY/SHELL ja if-1 12 13 tuottaa if-1: Hei!

Soita operaattorille ("tapaus")

"Tapauksen" valintaoperaattorilla on rakenne:

Kotelomerkkijono sisään

malli) komentoluettelo;; malli) komentoluettelo;; ... malli) komentoluettelo;;

Tässä "case", "in" ja "esac" ovat funktiosanoja. "merkkijonoa" (tämä voi olla yksi merkki) verrataan "kuvioon". Valitun rivin "komentoluettelo" suoritetaan sitten. ";;" näyttää epätavalliselta valintarivien lopussa, mutta kirjoita tähän ";". se olisi virhe. Kullekin vaihtoehdolle voidaan suorittaa useita komentoja. Jos nämä komennot on kirjoitettu yhdelle riville, symboli ";" käytetään komentojen erottimena. Tyypillisesti viimeisellä valintarivillä on kuvio "*", joka "case"-rakenteessa tarkoittaa "mitä tahansa arvoa". Tämä rivi valitaan, jos muuttujan arvo (tässä $z) ei vastaa mitään aiemmin kirjoitettuja kaavoja, jotka on rajattu ")" -sulkeella. Arvot näkyvät siinä järjestyksessä, jossa ne kirjoitettiin.

Enumeroitu silmukkaoperaattori ("for")

"for"-silmukkaoperaattorilla on rakenne:

Nimelle

do luettelo komennoista done, jossa "for" on apusana, joka määrittää silmukan tyypin, "do" ja "done" ovat apusanoja, jotka korostavat silmukan runkoa. Esitetään komento "lsort" erätiedostona

Kohdassa i tiedosto_1 tiedosto_2 tiedosto_3 do proc_sort $i done

Tässä esimerkissä nimi "i" toimii silmukkaparametrina. Tätä nimeä voidaan pitää shell-muuttujana, jolle luetellut arvot määrätään peräkkäin (i=file_1, i=file_2, i=file_3), ja "proc_sort"-komento suoritetaan silmukassa. Usein käytetään muotoa "for i in *", mikä tarkoittaa "kaikille tiedostoille nykyisessä hakemistossa". Esitetään "proc_sort" vuorostaan ​​erätiedostona

Kissa $1 | lajitella | tee /dev/lp > $(1)_lajiteltu

nuo. määritetyt tiedostot lajitellaan peräkkäin, lajittelutulokset tulostetaan ("/dev/lp") ja lähetetään tiedostoihin tiedosto_1_lajiteltu tiedosto_2_lajiteltu ja tiedosto_3_lajiteltu

Silmukan lauseke tosiehdon kanssa ("while")

"While"-rakenne, joka myös suorittaa laskelmia, on parempi, kun tarkkaa parametriarvojen luetteloa ei tiedetä etukäteen tai tämä luettelo on hankittava silmukan laskutoimituksen tuloksena. "while"-silmukkakäskyllä ​​on rakenne:

Kun kunto

do luettelo tehdyistä komennoista, jossa "while" on apusana, joka määrittää silmukan tyypin tosiehdon kanssa. Silmukan rungon komentoluetteloa ("do" ja "done" välillä) toistetaan, kunnes ehto pysyy tosi (eli silmukan rungon viimeisen komennon lopetuskoodi on "0") tai silmukkaa ei keskeytetä. sisältä erityisillä komennoilla ("break", "continue" tai "exit"). Kun astut silmukaan ensimmäisen kerran, ehdon on oltava tosi. "break [n]" -komennolla voit murtautua silmukasta. Jos "n" puuttuu, se vastaa "break 1". "n" osoittaa sisäkkäisten silmukoiden lukumäärän, joista poistutaan, esimerkiksi "break 3" - poistu kolmesta sisäkkäisestä silmukasta. Toisin kuin "break"-komento, "continue [n]" -komento vain pysäyttää nykyisen silmukan suorittamisen ja palaa silmukan ALKUUN. Se voi olla myös parametrilla. Esimerkiksi "jatka 2" tarkoittaa poistumista toisen (syvyydestä laskettuna) sisäkkäisen silmukan alkuun. "Exit [n]" -komennolla voit poistua proseduurista kokonaan paluukoodilla "0" tai "n" (jos parametri "n" on määritetty). Tätä komentoa voidaan käyttää muussakin kuin vain silmukoissa. Jopa lineaarisessa komentosarjassa voi olla hyödyllistä virheenkorjauksessa pysäyttää (nykyinen) laskenta tiettyyn kohtaan.

Silmukkalause, jossa on väärä ehto ("kunnes")

"Kunnes"-silmukkaoperaattorilla on rakenne:

Kunnes kuntoon

do luettelo komennoista tehty, jossa "kunnes" on apusana, joka määrittää silmukan tyypin, jossa on väärä ehto. Silmukan rungossa olevaa komentoluetteloa (välillä "do" ja "done") toistetaan, kunnes ehto pysyy epätosi tai silmukan keskeytetään sisältäpäin erityisillä komennoilla ("break", "continue" tai "exit" ). Kun astut silmukkaan ensimmäisen kerran, ehdon ei pitäisi olla tosi. Ero "while"-operaattoriin on se, että silmukan ehto tarkistetaan epätosi (silmukan rungon viimeisen komennon nollasta poikkeavalle poistumiskoodille) ja se tarkistetaan jokaisen komennon (mukaan lukien ensimmäinen!) suorittamisen JÄLKEEN silmukan runko. Esimerkki.

Kunnes vääriä tehdä

lue x, jos [$x = 5] niin kaiku tarpeeksi; break else echo some more fi

Tässä ohjelma odottaa äärettömässä silmukassa sanojen syöttämistä (toistaen "jotain lisää" näytöllä), kunnes "5" syötetään. Tämän jälkeen annetaan "riittävästi" ja "break"-komento lopettaa silmukan suorittamisen.

Tyhjä operaattori

Tyhjällä lauseella on muoto

:

Tekemättä mitään. Palauttaa arvon "0".

Toiminnot kuoressa

Toiminnon avulla voit valmistella komentotulkkikomentojen luettelon myöhempää suoritusta varten. Toiminnon kuvaus näyttää tältä:

Nimi() (komentoluettelo)

jonka jälkeen funktiota kutsutaan nimellä. Kun toiminto suoritetaan, uutta prosessia ei luoda. Se toimii vastaavan prosessin ympäristössä. Funktion argumenteista tulee sen sijaintiparametreja; funktion nimi on sen nollaparametri. Voit keskeyttää funktion suorittamisen käyttämällä "return [n]" -operaattoria, jossa (valinnainen) "n" on paluukoodi.

Keskeytyksen käsittely ("trap")

Saattaa olla tarpeen suojata ohjelman suoritus keskeytyksettä. Useimmiten kohtaat seuraavia signaaleja vastaavia keskeytyksiä: 0 poistuminen tulkista, 1 puhelun katkaisu (etätilaajan yhteyden katkeaminen), 2 keskeytys , 9 tuhoaminen (ei siepattu), 15 suorituksen loppu. Keskeytyksiä vastaan ​​suojaamiseksi on olemassa "trap"-komento, jonka muoto on:

Pysäytä "komentoluettelon" signaalit

Jos järjestelmässä esiintyy keskeytyksiä, joiden signaalit on listattu välilyönnillä erotettuina "signaaleissa", suoritetaan "komentoluettelo", jonka jälkeen (jos komentoluettelossa ei suoritettu komentoa "exit") ohjaus palaa keskeytyskohtaan ja komentotiedoston suoritus jatkuu. Jos esimerkiksi ennen komentotiedoston suorittamisen keskeyttämistä on tarpeen poistaa tiedostot "/tmp"-tiedostosta, tämä voidaan tehdä "trap"-komennolla:

Trap "rm /tmp/* ; exit 1" 1 2 15

joka edeltää tiedoston muita komentoja. Täällä, kun tiedostot on poistettu, komentotiedosto poistuu.

Varmasti melkein kaikki Habr-lukijat tuntevat sh- ja bash-kuoret. Useimmat meistä ovat myös kuulleet jotain zsh:sta ja tcsh:sta. Luettelo olemassa olevista kuorista ei kuitenkaan lopu tähän. Ne voidaan karkeasti jakaa kolmeen ryhmään:

  • Bourne shell -kloonit (bash, zsh)
  • C-kuori (csh, tcsh)
  • Perustuu suosittuihin ohjelmointikieliin (psh, ipython, scsh)
  • Eksoottista, erityistä ja kaikkea muuta
Mielenkiintoisimpia niistä keskustellaan.

Tämän artikkelin kirjoittamisen tarkoituksena ei ollut tarkastella tai luokitella kaikkia olemassa olevia komentotulkoja. Haluan vain puhua mielenkiintoisista tuotteista tällä alalla ja laajentaa lukijan näköaloja. Tulen olemaan iloinen. Jos tämä rohkaisee jotakuta tutkimaan aihetta tarkemmin tai jopa siirtymään toiseen aiheeseen.
Ensinnäkin lyhyesti mitä se on. Komentotulkki tai komentotulkki on sovellus, joka tarjoaa käyttäjälle komentoriviliittymän, jossa käyttäjä joko syöttää komentoja yksitellen tai suorittaa komentosarjoja, jotka koostuvat komentoluettelosta. Suullisesti ja epävirallisissa teksteissä sitä kutsutaan usein "kuoreksi", englannin kielestä - shell.

Yleisimmin käytetyt POSIX-yhteensopivat kuoret ovat peräisin Bourne-kuoresta, joten aloitamme siitä

Bourne-kuori ja sen kloonit

Bournen kuori, suoritettava tiedosto: sh. Komentotulkki, joka on nimetty sen luojan Stephen Bournen mukaan. Suurin osa operaattoreista lainattiin ALGOL 68 -kielestä. Se julkaistiin UNIX-käyttöjärjestelmän 7. painoksessa, jossa se oli oletuskuori. Toistaiseksi valtaosa Unixin kaltaiset järjestelmät on /bin/sh - symbolinen tai kova linkki sh-yhteensopivaan komentotulkkiin.

Bournen kuori taas, suoritettava tiedosto: lyödä. Otsikko voidaan kääntää "The Reborn Walk of Bourne". Todennäköisesti tämän päivän suosituin kuori. De facto standardi Linuxille. En aio jäädä siihen, koska... Internetissä on paljon hyviä artikkeleita bashista. Esimerkiksi täällä ja täällä.

Z kuori, suoritettava tiedosto: zsh. Ilmainen, moderni SH-yhteensopiva kuori. Sillä on monia etuja bashiin verrattuna, jotka liittyvät pääasiassa työskentelyyn interaktiivisessa tilassa. He kirjoittivat siitä Habrén ja
Lisäksi tähän ryhmään kuuluu melko vähän kuoria: Korn shell (ksh) ja Almquist shell (ash) jne, mutta emme käsittele niitä yksityiskohtaisesti.

C kuori

C kuori, suoritettava tiedosto: csh Kirjailija Bill Joyn kehittämä komentokulli. Perusteeksi skriptikieli csh on otettu, kuten nimestä voi päätellä, C-kielestä. tuolloin, vuonna 1978, se oli suosituin ohjelmointikieli BSD UNIX -kehittäjien ja käyttäjien keskuudessa. Tällä hetkellä suosituin ilmainen csh-toteutus on tcsh.

TENEX C Shell, suoritettava tiedosto: tcsh. Automaattinen täydennys ilmestyi ensimmäisen kerran tcsh:ssa. Tämä on FreeBSD:n oletuskuori. Voit lukea siitä lisää.
Jotta syntaksin erot näyttäisivät selkeästi, annan useita esimerkkejä skripteistä, jotka tekevät saman asian csh:lle ​​ja sh-yhteensopivalle komentotulkinnalle.

Ehdollinen rakenne:

Silmukka, joka laskee kahden ensimmäiset 10 potenssia:

#!/bin/sh i=2 j=1, kun taas [ $j -le 10]; do echo "2 **" $j = $i i=`lause $i "*" 2` j=`lause $j + 1` valmis #!/bin/csh joukko i = 2 joukko j = 1 while ($j<= 10) echo "2 **" $j = $i @ i *= 2 @ j++ end

Uusimpien bash-, zsh- ja tcsh-versioiden tukemien ominaisuuksien luettelo on kuitenkin hyvin samankaltainen, ja tietyn kuoren valinta on enimmäkseen makuasia. Harvempien kuorien kanssa tilanne on toinen. Tässä erot ovat suurempia.

Suosittuihin ohjelmointikieliin perustuvat komentotulkit.

Perl Shell, suoritettava tiedosto: psh. Shell, joka yhdistää yllä olevien kuorien ominaisuudet ja Perl-kielen voiman. Koska psh on kirjoitettu perlissä ja voi jopa toimia Windowsissa. Muutamia esimerkkejä psh:n käytöstä:
ls | s/y/k/ # Korvaus säännöllisillä lausekkeilla ls | ( tulosta ++$i, ": $_"; )q # Pikasuodatin. Aaltosulkeiden sisällä on Perl-lauseke, jossa $_ sisältää yhden tulosteen rivin. netstat | ( $_>2; )g # grep-suodattimet. Vain ne rivit tulostetaan, joille suluissa oleva lauseke palauttaa tosi-komennon >[=FOO] # Uudelleenohjaus kahvalla avaa tiedosto komento > tiedosto # Vastaa komentoa 2> tiedosto bashissa. Ohjaa lähdön ja virhevirran tiedostoon grep foo lib/**/*.pm # Käytä **, mikä tarkoittaa nykyistä hakemistoa ja kaikkia alihakemistoja

Scsh, suoritettava tiedosto scsh. Avoimen lähdekoodin komentotulkki, joka käyttää Scheme 48:aa komentosarjakielenä. Ei tue muiden komentotulkkien vakiotoimintoja (komentohistoria, tekstin muokkaus komentorivillä, polun/komennon lisäys). Komentosarja on suositeltavaa, mutta ei interaktiivista työtä. Voi vetoaa toiminnallisen ohjelmoinnin ystäviin. Alla on esimerkki komentosarjasta, joka näyttää kaikkien PATH-ympäristömuuttujan hakemistoissa olevien suoritettavien tiedostojen nimet
! x) (uusirivi)) (jokaiselle writeln:lle (lisää-map suoritettavat tiedostot ((infix-splitter ":") (getenv "PATH"))))

IPython. Se on Python-ohjelmointikielen interaktiivinen kuori, ja siinä on useita lisätoimintoja. IPythonilla on erityinen profiili järjestelmäkuoren käyttöä varten. Tapa käynnistää tämä tila riippuu ymmärtääkseni versiosta, mutta koneessani se näyttää tältä:
ipython3 --profile=pysh

IPythonista on jo kirjoitettu melko paljon, myös venäjäksi (linkit artikkelin lopussa). Yritän luetella sen tärkeimmät ominaisuudet sen käyttämisen kannalta komentotulkina:

  • Cross-platform. Siitä on jopa Windows-versio
  • Python-versiot 2.x tai 3.x komentosarjakielenä, parannetut itsetutkiskeluominaisuudet
  • Python-koodin automaattinen täydennys sekä tiedostonimien ja järjestelmän komennot.
  • Komentohistoria ja siihen perustuvat makrot
  • Mekanismi, joka nopeuttaa navigointia luetteloissa, kirjanmerkeissä ja monessa muussa
Kuten näet, omalla tavallasi interaktiivisia ominaisuuksia IPython on vähintään yhtä hyvä kuin bash. Mitä tulee komentosarjoihin, IPython on kätevä niille, jotka tuntevat pythonin paremmin kuin bashin. Itse asiassa IPython-skriptit eroavat puhtaasta Pythonista vain järjestelmäkomentojen yksinkertaistetussa kutsumisessa. Tässä on joitain esimerkkejä python- ja järjestelmäkomentojen integroinnista:
# Oletetaan, että halusimme laskea dpkg-lokitiedostojen kokonaiskoon: Sisään : cd /var/log/ /var/log Sisään : log_files = !ls -l dpkg.log* Sisään : log_files Out: "-rw-r- -r-- 1 juurijuuri 1824 3. marraskuuta 16:41 dpkg.log" Sisään : riville lokitiedostoissa: ....: koko += int(line.split()) ....: Sisään : koko Out: 1330009 # ..tai ping peräkkäin kymmenen isäntää In : for i in range(100,110): ....: !ping -c 1 192.168.0.$i ....:
Levätä
Tämä ei tietenkään ole täydellinen luettelo jopa suosituista kuorista. Yllä olevien luokkien lisäksi on myös sellaisia, jotka käyttävät omaa syntaksiaan, joka ei ole yhteensopiva sh:n kanssa eikä kopioi olemassa olevaa kieltä. Esimerkkinä voisi olla ystävällinen interaktiivinen kuori (kala). Mutta lopuksi, en halua puhua siitä, vaan tarkemmasta unenkuoresta.

Sleep Dummy Shell, suoritettava tiedosto: unikuori. Tarkkaan ottaen unikuorta ei voida kutsua komentoprosessoriksi, koska se ei voi käsitellä komentoja. Ja yleensä se ei voi tehdä muuta kuin kirjoittaa säännöllisesti tähtiä "*" vakiotulostukseen. Sitä käytetään kuitenkin nimenomaan komentotulkina ja tästä syystä: Oletetaan, että haluamme antaa jollekulle mahdollisuuden tehdä ssh-tunneleita Linux- tai Unix-palvelimemme kautta. Lue lisää ssh-tunneluksesta. Mutta emme tarvitse, että jollakulla on pääsyä palvelimemme komentoriville ja tiedostojärjestelmään. Sleepshell on suunniteltu sellaiseen tapaukseen. Luomme palvelimelle tilin komentotulkina ja asennamme siihen nukkumiskuoren. Tilin omistaja voi yhdistää ja välittää portteja, mutta ei voi suorittaa komentoja.

Siinä kaikki. Toivottavasti oli mielenkiintoista. Otan mielelläni vastaan ​​kommentteja ja neuvoja artikkelin tekstistä.

Liittyvät linkit
www.faqs.org/faqs/unix-faq/shell/shell-differences - pivot-taulukko erot ja yhtäläisyydet kuorien välillä
www.mariovaldez.net/software/sleepshell - Sleep Dummy Shell
ipython.org/ipython-doc/dev/interactive/shell.html - IPython järjestelmän kuorena
www.opennet.ru/base/dev/ipython_sysadmin.txt.html - IPython-kuori järjestelmänvalvojan työkaluna