4.4  Muuttujat

4.4.1  Sisäiset muuttujat

Yksinkertaisia muuttujia luodaan ja niille asetetaan arvo tyyliin

varname=value

Huom. yhtäsuuruusmerkin ympärillä ei saa olla välilyöntejä.

Muuttujanimessä sallittuja merkkejä ovat kirjaimet, numerot ja alaviiva; ensimmäisen on oltava kirjain.

Muuttujan arvoon viitataan syntaksilla $varname tai ${varname}; ts. jos komentorivillä esiintyy  $varname, se korvataan muuttujan varname arvolla.

Muuttujanimi on suljettava aaltosulkuihin silloin, kun seuraavakin merkki voisi olla osa muuttujanimeä (se on kirjain, numero tai alaviiva). Vertaa:

K=a
Kalle=n
echo $Kalle
echo ${K}alle

Muuttujan voi hävittää komennolla unset varname (yksitellen - POSIXin unset ei ymmärrä mitään jokerimerkkejä).

Muuttujasta voi tehdä vakion komennolla readonly varname[=value]. Kaikki vakiot voi listata komennolla readonly -p. Vakion arvoa ei voi muuttaa eikä sitä voi hävittää unsetilla.

4.4.2  Ympäristömuuttujat

Ympäristömuuttujat eroavat sisäisistä siinä, että ne periytyvät aliprosesseille. Muuttujan voi määritellä ympäristömuuttujaksi komennolla export. Käänteistä toimintoa ei ole mutta ympäristömuuttujankin voi hävittää unsetilla.

export varname...

Lisäksi jos optio -a on voimassa, kaikista luotavista muuttujista tulee automaattisesti ympäristömuuttujia. Ympäristömuuttuja voi olla vakio (readonly), mutta readonly-attribuutti ei välttämättä periydy (riippuu shellistä).

4.4.3  Erikoisparametrit

Edellisten lisäksi shell käyttää joukkoa erikoismuuttujia, jotka tunnistaa siitä, että ne eivät ala kirjaimella. Niitä ei voi exportata ja ne käyttäytyvät joissakin tilanteissa muutenkin eri tavoin kuin normaalit muuttujat.

Jos sh-skriptille annetaan argumentteja (optioiden lisäksi), ne talletetaan ns. positioparametreihin (positional parameters) $1, $2,... (Funktion sisällä positioparametrit viittaavat funktion kutsussa annettuihin argumentteihin, kuten edellä on todettu.)

Sen lisäksi sh määrittelee automaattisesti seuraavat parametrit:

* Kaikki positioparametrit yhtenä merkkijonona
@ Kaikki positioparametrit erillisinä
0 skriptin nimi
# Positioparametrien lukumäärä
? Viimeksi suoritetun komennon palauttama status
- Voimassa olevat optiot
$ Shellin process id
! Viimeksi käynnistetyn taustaprosessin id

Kaksi ensimmäistä tarvitsevat lisäselitystä. Ne eroavat toisistaan ainoastaan siinä, miten ne käyttäytyvät tuplalainausmerkeissä ": "$*" on yksi merkkijono joka sisältää kaikki parametrit välilyönnillä eroteltuina (tai oikeammin $IFS:n ensimmäisellä merkillä - enemmän siitä myöhemmin). Ts. echo "$*" käyttäytyy kuin
echo "$1 $2 $3 ..."

"$@" taas toimii kuin kaikki parametrit olisi yksitellen suljettu lainausmerkkeihin:
echo "$1" "$2 "$3" ....

4.4.4  Systeemimuuttujat

POSIX määrittelee seuraavat yleiset ympäristömuuttujat - ei vaadi että niiden pitäisi olla olemassa mutta jos ne ovat, niiden merkityksen pitää olla tämä:

HOME Käyttäjän kotihakemisto
LANG Oletuskieli (locale) niille, joille sitä ei ole erikseen määrätty LC_*-muuttujalla
LC_ALL Kieliasetus - ohittaa LANG- ja muut LC_*-muuttujat
LC_COLLATE Kieliasetus aakkosjärjestyksen määräämiseen (lajittelu, regexp-luokat)
LC_CTYPE Kieliasetus merkkien luokitteluun (määrää mitkä ovat numeroita ja kirjaimia jne)
LC_MESSAGES Kieliasetus systeemin viesteille
LC_MONETARY Kieliasetus rahamäärien muotoilulle
LC_NUMERIC Kieliasetus lukujen muotoilulle (esim. desimaalipilkku vs. -piste)
LC_TIME Kieliasetus päivämäärän ja kellonajan muotoilulle
LOGNAME Käyttäjätunnus
PATH Hakupolku, lista tiedostoista joista komentoja etsitään, eroteltuina kaksoispisteillä. Tyhjä (kaksi peräkkäistä kaksoispistettä tai kaksoispiste alussa tai lopussa) vastaa oletushakemistoa (.) - tätä ei kuitenkaan pitäisi käyttää vaan mieluummin eksplisiittistä pistettä jos sitä halutaan.
SHELL Käyttäjän oletusshell
TMPDIR Käyttäjien kirjoitettavissa oleva tilapäinen hakemisto
TERM Päätetyyppi
TZ Aikavyöhyke

Nuo ovat siis periaatteessa yhteisiä kaikille komennoille. Lisäksi yksittäiset POSIXin tuntemat komennot käyttävät seuraavia muuttujia:

CDPATH (cd), COLUMNS (ls), DEAD, MAILRC (mailx), IFS (sh), LPDEST, PRINTER (lp), MAKEFLAGS (make), OPTARG, OPTIND (getopts).

Näihin palataan tarkemmin myöhemmin.

4.4.5  sh:n toimintaan vaikuttavat ympäristömuuttujat

POSIX määrittelee sh:n ei-interaktiiviseen toimintaan vaikuttaviksi vain muuttujat HOME, PATH, LANG, LC_ALL, LC_COLLATE, LC_CTYPE ja LC_MESSAGES, jotka on kuvattu edellä, sekä sh-spesifin muuttujan IFS.

IFS (Input Field Separators) määrittelee erotinmerkit syöttörivien lukemiseen ja parametrien ja komentokorvauksen tulosten kenttien erotteluun (siitä enemmän näiden yhteydessä). Oletusarvo on välilyönti + tab + newline (myös jos sitä ei ole asetettu lainkaan, mutta ei jos se on tyhjä).

POSIX.2 välttää ottamasta kantaa sh:n interaktiiviseen käyttöön, mutta luettelee kuitenkin seuraavat siihen mahdollisesti vaikuttavia muuttujia:

ENV FCEDIT HISTFILE HISTSIZE LINENO MAIL PPID PS1 PS2 PS4

Osa näistä vaikuttaa ainakin epäsuorasti skripteihinkin, joten palaamme niihin myöhemmin. (Ksh käyttää muuttujaa PS3 select-komennossaan.)

4.4.6  Muuttujien käsittely

Muuttujien (ja parametrien) arvoon viitatessa niille voi samalla tehdä joitakin testejä ja muokkaustoimintoja. Yleinen syntaksi on ${varname oper [arg]}
eli ${}:n sisällä muuttujan nimen perään lisätään operaattorimerkki ja sen argumentti.

Seuraavat testaavat muuttujien olemassaoloa:

${varname:-word} Jos nimetty muuttuja on olemassa ja epätyhjä, palauttaa sen arvon, muuten tekstin word.
${varname:=word} Kuten yllä, mutta lisäksi asettaa muuttujan arvoksi word
${varname:+word} Jos nimetty muuttuja on olemassa ja epätyhjä, palauttaa tekstin word, muuten tyhjän.
${varname:?message} Jos nimetty muuttuja on olemassa ja epätyhjä, palauttaa sen arvon, muuten aiheuttaa virheen viestinä varname: message (tai varname: parameter null or not found jos message on tyhjä)

Kaikissa noissa kaksoispisteen voi jättää pois, jolloin ne hyväksyvät myös tyhjän muuttujan.

Seuraavilla voi muokata (tutkia) muuttujan arvoa, tai palauttaa vain osan siitä:

${#varname} Palauttaa muuttujan pituuden (merkkeinä)
${varname%pattern} Poistaa muuttujan lopusta lyhimmän patternia vastaavan merkkijonon, jos mahdollista, ja palauttaa tuloksen (ei muuta itse muuttujaa)
${varname%%pattern} Kuten yllä, mutta poistaa lopusta pisimmän mahdollisen merkkijonon
${varname#pattern} Kuten yllä, mutta poistaa alusta lyhimmän merkkijonon
${varname##pattern} Kuten yllä, mutta poistaa alusta pisimmän mahdollisen merkkijonon

4.4.7  Positioparametrien käsittely: shift ja set

Positioparametrien käsittelyyn on kaksi erityiskomentoa (funktion sisällä nevaikuttavat funktion parametreihin):

shift [n]

hukkaa n ensimmäistä parametria ($0:aa ei lueta mukaan) ja siirtää seuraavia vastaavasti alkuun päin ($n:stä tulee $1 jne).

set [--] par1 ...

asettaa kerralla kaikki positioparametrit uusiksi. Rajoitin -- tarvitaan jos ensimmäinen parametri alkaa viivalla. (Näin siksi että set-komennolla on toinenkin tehtävä: sillä voi asettaa shellin optioita.)

4.4.8  Muuttujan tilapäinen sijoitus

Muuttujalle voi antaa arvon vain yhden komennon suorituksen ajaksi:

var=value command

Tällöin muuttuja asetetaan suoritettavan komennon ympäristöön mutta asetus ei jää voimaan komennon päätyttyä. (Poikkeuksena erityiset sisäiset komennot, joista myöhemmin enemmän.)

4.4.9  Ksh: tyypitetyt muuttujat ja taulukot

Bourne sh ja POSIX sen myötä tuntee vain yhdentyyppisiä muuttujia, merkkijonoja, joita sitten voidaan tarvittaessa tulkita luvuiksikin. Ksh88 tuntee erillisen kokonaislukutyypin, taulukot sekä joukon muita ominaisuuksia joita muuttujille voi määritellä. Ksh93 tuntee liukuluvutkin.

Muuttujille annetaan tyyppi komennolla typeset, jolla on melkoinen liuta optioita, seuraavassa tärkeimmät:

-i kokonaislukumuuttuja
-l merkkijono jossa isot kirjaimet muutetaan automaattisesti pieniksi
-u merkkijono jossa pienet kirjaimet muutetaan automaattisesti isoiksi
-r read-only muuttuja, jota ei voi sen jälkeen muuttaa

Taulukota puolestaan voi luoda komennolla
set -A nimi alkio1 alkio2 ...
tai alkioittain tyyliin x[0]=a, ja taulukon alkioihin viitataan tyyliin ${x[a]}. Alkioiden indeksointi alkaa nollasta ja yläraja voi olla suhteellisen pieni (ksh88:ssa 1023).

4.5  Syöttö ja tulostus

4.5.1  Uudelleensuuntaus

Komentojen (mukaanlukien funktiot) syöttöä ja tulostusta voi ohjata seuraavilla tavoilla:

n > file Ohjaa tiedostokahvan n (tai sen puuttuessa 0:n eli standard outputin) tiedostoon file; jos tiedosto on ennestään olemassa se tuhoutuu, tai jos noclobber -optio on voimassa, aiheutuu virhe. tulostuksen tiedostoon file
n < file Ohjaa tiedostokahvan n (tai sen puuttuessa 1:n standard inputin) lukemaan tiedostosta file
n >> file Kuten > mutta kirjoittaa mahdollisesti olemassaolevan tiedoston loppuun.
n > | file Kuten > mutta tuhoaa olemassaolevan tiedoston optiosta noclobber riippumatta
n < > file Kuten > mutta suuntaa sekä syötön että tulostuksen
n << word Kääntää syötön lukemaan perässä seuraavaa tekstiä (ns. here-document) sanaan word saakka
n > &m Kääntää tiedostokahvan n (tai stdoutin) tulostuksen ennestään auki olevaan tiedostokahvaan m, tai jos m:n paikalla on -, sulkee tiedostokahvan n
n < &m Kääntää tiedostokahvan n (tai stdinin) lukemaan auki olevasta tiedostokahvasta m, tai jos m:n paikalla on -, sulkee tiedostokahvan n
cmd1| cmd2 Ohjaa cmd1:n stdoutin cmd2:n stdiniin. Huom. cmd2 saatetaan suorittaa samassa (ksh tekee näin) tai alishellissä; yleensä siihen ei voi luottaa kumminkaan päin.

Ksh tuntee lisäksi seuraavat:

cmd|& Käynnistää co-prosessin: siirtää komennon suorituksen taustalle mutta jättää sen I/O:n sidotuksi emoprosessiin
n > &p ohjaa tulostuksen co-prosessille
n < &p ohjaa syötön co-prosessille

Huom. Tiedostokahvanumero n pitää erottaa edeltävästä tekstistä välilyönnillä tms, ja toisaalta sen ja siihen kuuluvan uudelleensuuntausmerkin välissä ei saa olla välilyöntiä. (Sen jäljessä, ennen tiedostonimeä, tyhjää saa olla muttei tarvita.) Vertaa seuraavia:

cat file22>foo
cat file2 2>bar
echo 1 2>foo
echo 1 2 >bar

Tiedostonumeron yläraja on toteutuskohtainen, kuitenkin ainakin 0-9 toimivat aina, ja 0 (stdin), 1 (stdout) ja 2 (stderr) ovat valmiiksi auki.

Uudelleensuuntausmerkit tulkitaan ennen komentoa, niinpä ne voi sijoitella komentoriville melko vapaasti. Vertaa:

echo kala >fisu
>fisu echo kala
echo >fisu kala
echo 4 + 2 > 5 - 3
echo 4 + 2> 5 - 3
echo 4 +2> 5 - 3
echo 4+2>5-3

Huom. erityiset sisäiset komennot ja varatut sanat voivat käyttäytyä poikkeavasti tässä suhteessa. Pääsääntöisesti uudelleensuuntaukset kannattanee sijoittaa komennon jälkeen.

4.5.2  Here-dokumenteista

Ns. here-document on erikoistapaus uudelleensuuntauksesta: se ohjaa syötön tulemaan skriptissä itsessään seuraavasta tekstistä rajasanaan saakka. Jos sana tai sen osakin on suojattu, teksti luetaan sellaisenaan, muussa tapauksessa tekstilaajennukset tehdään kuten tuplalainausmerkeissä. Lisäksi sanan alussa mahdollisesti oleva tavuviiva tarkoittaa sisennystä tab-merkeillä (ei välilyönnein).

Esim. Tulostetaan muuttujien X, Y ja Z nimet ja arvot:

cat <<EOF
X=$X
Y=$Y
Z=$Z
EOF

4.5.3  Command substitution

Komennon tulostuksen voi muuttaa merkkijonoksi komentorivillä kahdella vaihtoehtoisella syntaksilla:

  1. takaheittomerkillä ` komennon molemmin puolin:
    x=`date`
  2. dollaria seuraavilla suluilla:
    x=$(date)

Jälkimmäinen on jokseenkin aina parempi vaihtoehto, se on selkeämpi erityisesti useampia sisäkkäisiä korvauksia käytettäessä ja erikoismerkkien suojaussääntö sille on parempi.

Ksh (mutta ei POSIX) tuntee erikoistapauksena syntaksin $(<file), joka tekee olennaisesti saman kuin $(cat file) käynnistämättä uutta prosessia.

4.5.4  read

Komento

read [-r] muuttujalista

lukee yhden rivin stdinistä (jonka tietty voi uudelleensuunnata), ja purkaa sen $IFS:n sisällön rajaamiin kenttiin ja tallettaa tulokset listan muuttujiin. Jos muuttujia on liian vähän, kaikki loput kentät talletetaan viimeiseen, jos liikaa, viimeiset jäävät tyhjiksi. Jos rivi loppuu kenoviivaan, lukee seuraavankin rivin paitsi jos -r optio on annettu.

Esim. Mitä seuraava tekee? Miksi? Vertaa ksh:ta ja bashia.

echo a b | read x
echo $x

4.5.5  IFS

Muuttuja IFS vaikuttaa syöttöön sen verran monimutkaisella tavalla, että se ansaitsee oman kappaleensa.

POSIXin mukaisissa shelleissä IFS vaikuttaa vain muuttuja- ja komentokorvauksen tulokseen, ei kuitenkaan tuplalainausmerkkien sisällä, sekä read-komentoon. Vanhemmissa shelleissä se saattaa vaikuttaa komentorivin tulkintaan muutenkin.

IFS:n eri arvot vaikuttavat seuraavasti:

  1. Jos IFS on (oletusarvo) välilyönti+tab+rivinvaihto, tai sitä ei ole lainkaan, ko. merkit syötön alussa ohitetaan ja mielivaltainen ei-tyhjä joukko niitä toimii yhtenä erottimena.
  2. Jos IFS on tyhjä, kenttiä ei pilkota lainkaan.
  3. Muussa tapauksessa sovelletaan järjestyksessä seuraavia:

    1. IFS:n mahdollisesti sisältämät tyhjämerkit ohitetaan rivin alussa ja lopussa
    2. jokainen ei-tyhjä IFS:n merkki ja sen ympärillä mahdollisesti olevat tyhjät IFS:n merkit tulkitaan yhdeksi erottimeksi
    3. ei-tyhjä joukko IFS:ssä olevia tyhjiä tulkitaan yhdeksi erottimeksi

Esimerkki:
echo x , y   z |(IFS=' ,' read a b c; echo "a=$a,b=$b,c=$c")
a=x,b=y,c=z

Huom. Tämä tuntuu olevan vaikea asia, etenkin viimeinen kohta; esim. bash ei osaa sitä ainakaan vielä versiossa 2.03. Yleensä ei kannattane käyttää IFS:ssä oletuksen lisäksi kuin yksimerkkisiä arvoja (ja sittenkin varautua siihen että tyhjiä hukkuu kuitenkin).

Lisää esimerkkejä:

x='1 + 2'
expr $x
IFS=:
expr $x
expr 1 + 2

4.5.6  echo

Echo tulostaa merkkijonon stdout'iin. Sillä ei ole mitään siirrettäviä optioita: SysV:n ja BSD:n versiot olivat liian erilaisia että POSIXkaan olisi saanut niitä yhdistettyä.

BSD:n echo tuntee yhden option: -n, joka jättää rivinvaihdon tulostuksesta pois.

SysV:n echo ei tunne optioita mutta sen sijaan tulkitsee argumenteissaan olevia kenoviivoja seuraavasti:

\b backspace
\c jättää rivinvaihdon pois
\f formfeed (sivunvaihto)
\n ylimääräinen rivinvaihdon
\r cr (telanpalautus)
\t tab
\v vertical tab
\\ \
\0num oktaalilukua num vastaava merkki

Gnu-projektin echo toimii kuten BSD:n mutta tunnistaa lisäksi option -e, joka saa sen tulkitsemaan kenoviivan sysV:n tyyliin. (Gnu echo:n uudemmat versiot tuntevat muitakin optioita.)

Yleisesti echoa ei voi käyttää siirrettäväksi aiotussa skriptissä jos pitää tulostaa kenoviivoja, viivalla alkava rivi tai jotakin ilman rivinvaihtoa.

4.5.7  Ksh: print

Ksh tarjoaa echon korvikkeeksi komentoa print. Se ymmärtää sekä BSD:n echo:n -n -option että samat kenoviivakonventiot kuin SysV:n echo, mutta ne saa pois päältä optioilla -r. Muista optioista mainittakoon -un, joka ohjaa tulostuksen tiedostokahvaan n, sekä -p, joka ohjaa sen co-prosessille.

4.5.8  printf

printf format [arguments...]

tarjoaa muotoillun tulostuksen suunnilleen samalla tavalla kuin C:n printf() (liukulukutulostusta lukuunottamatta). Lisäformaattina %b ymmärtää samat kenoviivakonventiot kuin sysV:n echo. Formaateilla b, c ja s argumentti tulkitaan aina merkkijonoksi, muuten C:n mukaisesti.

Jos argumentteja on enemmän kuin formaatissa kenttämäärityksiä, formaattia käytetään uudelleen alusta.

Haluttaessa vähänkään monimutkaisempaa tulostusta, printf on ainoa edes kohtuullisen siirrettävä keino.

Seuraava: 4.6 Shellin jokerimerkit
Edellinen: 4.1-4.3 Skriptien suoritustavat, funktiot, erikoismerkkien suojaus


File translated from TEX by TTH, version 1.98.
On 17 May 2001, 18:13.