Hoppa yfir í efnið

Pípur og staðalstraumar

Ein öflugasta hugmyndin í Linux er hvernig forrit geta talað saman. Í stað þess að smíða eitt risastórt forrit sem gerir allt getum við skeytt saman mörgum litlum forritum til að framkvæma flókin verkefni.

Staðalstraumar

Sérhvert forrit sem keyrir í Linux opnar sjálfkrafa þrjár samskiptarásir sem kallast staðalstraumar (e. standard streams):

  1. Staðalinntak (e. stdin): Hér hlustar forritið. Oftast kemur þetta frá lyklaborðinu.
  2. Staðalúttak (e. stdout): Hér talar forritið. Oftast fer þetta á skjáinn.
  3. Staðalvilla (e. stderr): Sérstök rás fyrir villumeldingar.

Af hverju tvö úttök?

Ef forrit á að skila gögnum viljum við ekki endilega blanda villumeldingum saman við gögnin. Með sérstöku stderr getum við visað niðurstöður og villur á mismunandi stöðum.

Með því að keyra skipanirnar

cd ~/examples
ls welcome.txt engin-svona-skra.txt
má sjá hvernig önnur línan birtir venjulegt úttak á meðan hin sýnir villu. Þótt þær birtist báðar í skeljaglugganum heldur Linux utan um þær sem tvo aðskilda strauma.


Hefðin: skrá sem viðfang eða gögn úr staðalinntaki

Mörg klassísk Linux-forrit fylgja þeirri mikilvægu hefð að ef skrá eða gögn eru gefin sem viðfang þá vinnur forritið með þau, en ef ekkert viðfang er gefið les það úr staðalinntaki.

Þetta er ein helsta ástæðan fyrir því að pípur virka svona vel, þar sem sama forritið getur bæði unnið beint úr skrá og tekið við gögnum frá öðru forriti. Til dæmis mun skipunin sort (stytting á sort) skila sömu raðanlegu niðurstöðunni á mismunandi hátt:

sort data/names.txt              # sort les skrána data/names.txt
cat data/names.txt | sort        # sort les sömu gögn úr stdin

Fleiri dæmi á borð við notkun á skipuninni wc (stytting á word count) og grep (stytting á global regular expression print):

wc -l skjal.txt            # telur línur í skrá
cat skjal.txt | wc -l      # telur línur sem koma úr pípu

grep "Halló" skjal.txt     # leitar í skrá
cat skjal.txt | grep "Halló"  # leitar í stdin
sýna hversu auðveldlega við getum hugsað um skipanir eins og litlar vélar á færibandi, þar sem ein vél býr til eða les texta, næsta raðar honum, og sú þriðja síar eða telur línur.

Ekki öll forrit fylgja hefðinni fullkomlega

Mörg textavinnslutól gera þetta, t.d. sort, grep, wc, sed og awk. Sum forrit þurfa samt alltaf skráarnafn eða nota aðra hegðun. Ef þú ert óviss er best að skoða --help eða man.

Prófaðu: sömu gögn, tvær leiðir

Notaðu sort og wc -l bæði með skráarnafni og með pípu.

Lausn

Við getum framkvæmt þetta á tvo vegu með því að keyra skipanirnar

sort data/names.txt
cat data/names.txt | sort

wc -l data/names.txt
cat data/names.txt | wc -l
sem sýnir hvernig pípur geta leyst sama verkefni og bein skráarvinnsla.


Endurvísun

Endurvísun (e. redirection) breytir því hvaðan forrit les eða hvert það skrifar í skráakerfinu.

Úttak í skrá: > og >>

Með því að nota endurvísunartáknin getum við keyrt skipanir á borð við

ls > listi.txt       # býr til eða yfirskrifar
ls >> listi.txt      # bætir aftan við
til að beina úttaki annaðhvort í nýja eða núverandi textaskrá.

Inntak úr skrá: <

Á sama hátt er hægt að keyra skipunina

sort < data/names.txt
til að lesa inntak beint úr tilgreindri skrá. Þótt mörg forrit taki skráarnafn sem viðfang, minnir < okkur á að gögnin eru lesin úr staðalinntaki.

Villur í skrá: 2>

Þegar við viljum sía út og vista villuboð sérstaklega getum við beitt skipuninni

find / -name "skjal.txt" 2> villur.log
sem beinir öllum villum úr stderr yfir í skrána villur.log.

Allt í eina skrá: 2>&1

Ef við kjósum að beina bæði venjulegu úttaki og villuboðum á sama staðinn getum við keyrt

skipun > allt.txt 2>&1
sem þýðir að stdout sendist í allt.txt og stderr á sama stað. Hér skiptir röðin miklu máli því við skilgreinum fyrst hvert venjulegt úttak fer og tengjum villustrauminn svo við þá slóð.

Senda í svartholið: /dev/null

Ef við viljum hreinlega farga úttaki eða villuboðum sem við höfum engan áhuga á getum við notað skipanir eins og

skipun > /dev/null
skipun 2> /dev/null
þar sem /dev/null virkar sem svarthol sem eyðir öllum gögnum sem þangað eru send.

Prófaðu: vista úttak

Vistaðu raðaðan lista af nöfnum í playground/sorted-names.txt og bættu svo línufjölda aftan við sömu skrá.

Lausn

Við getum notað endurvísun og fylgt þessum skrefum

sort data/names.txt > playground/sorted-names.txt
wc -l data/names.txt >> playground/sorted-names.txt
cat playground/sorted-names.txt
sem býr fyrst til skrána og bætir svo línufjöldanum aftan við.

Prófaðu: aðskilja villur og úttak

Láttu ls reyna að sýna eina skrá sem er til og eina sem er ekki til. Vistaðu venjulegt úttak og villur í sitthvora skrána.

Lausn

Til þess að aðskilja staðalúttak og staðalvillu getum við keyrt skipunina

ls welcome.txt engin-svona-skra.txt > playground/ut.txt 2> playground/villur.txt
cat playground/ut.txt
cat playground/villur.txt
sem sýnir okkur vel hvernig straumarnir tveir vistast í sitthvorri skránni.


Pípur: |

Pípa tengir staðalúttak einnar skipunar beint við staðalinntak annarrar, sem við getum táknað með flæðinu

forrit1 | forrit2 | forrit3
þar sem gögnin streyma í gegnum öll forritin í röð.

Sem dæmi getum við notað keðjuna, þar sem tekin er inn skipunin uniq (stytting á unique):

cat data/names.txt | sort | uniq
til að lesa nöfn úr skrá, raða þeim í stafrófsröð og fjarlægja allar samliggjandi endurtekningar.

Með því að vinna með tilbúnu æfingagögnunum okkar getum við prófað að keyra skipanir á borð við

cat notes/duplicate_lines.txt | sort | uniq
cat notes/duplicate_lines.txt | sort | uniq -c
sem sýna okkur annaðhvort hreinsaðan texta eða nákvæman talningu á því hve oft hver lína kemur fyrir.

Oft má sleppa cat

cat skrá.txt | grep orð virkar, en grep orð skrá.txt er einfaldara. cat er samt stundum gagnlegt þegar við erum að hugsa um pípuna sem færiband.


Litir og pípur

Mörg forrit geta greint hvort staðalúttakið þeirra fer beint í skeljagluggann eða áfram í pípu eða skrá. Þegar úttakið fer beint á skjáinn er oft gagnlegt að nota liti, en þegar úttakið fer í pípu geta litir verið til vandræða þar sem þeir samanstanda af sérstökum stýritáknum inni í textanum.

Þess vegna slökkva mörg forrit sjálfkrafa á litum þegar þau sjá að úttakið fer ekki beint á skjá, sem við getum sannreynt með því að keyra

ls --color=auto
ls --color=auto | cat
þar sem fyrri skipunin sýnir litaðar skrár en sú seinni skilar venjulegum texta vegna þess að úttakið fer í gegnum cat.

Sama á við þegar við keyrum skipanir á borð við

grep --color=auto "root" /etc/passwd
grep --color=auto "root" /etc/passwd | cat
þar sem litunin á leitarorðinu hverfur oft í seinna skiptið þegar gögnum er pípað áfram.

Þvingaðir litir

Sum forrit leyfa þér að stjórna þessu, t.d. með --color=always, --color=auto eða --color=never. Ef þú notar --color=always í pípu geta litakóðarnir ferðast áfram og stundum ruglað önnur forrit sem eiga að vinna með hreinan texta.


Algeng tól í pípum

Skipun Hlutverk
sort Raðar línum
uniq Fjarlægir eða telur endurteknar línur sem standa saman
wc Telur línur, orð og bæti
cut Klippir út dálka eða stafi
tr Skiptir út eða eyðir stöfum
tee Skrifar bæði á skjá og í skrá
sed Breytir textastraumi línu fyrir línu
awk Vinnur með dálka og mynstur
xargs Breytir línum úr inntaki í viðföng fyrir skipun

tee: sjá og vista í einu

Skipunin tee (dregið af T-stykki í pípulögnum) virkar eins og T-stykki í vatnslögn þannig að úttakið fer bæði á skjáinn og í tilgreinda skrá. Við getum prófað þetta með því að keyra

ls -la | tee listi.txt
sem sýnir okkur listann beint á meðan hann skrifast í listi.txt.

Prófaðu einnig að nota skipunina cut (stytting á cut) og keyra:

cut -d, -f1 data/scores.csv | tee playground/names-from-csv.txt
til að sía út fyrsta dálkinn úr CSV-skránni og vista hann samtímis á nýjum stað.

tr: breyta stöfum

Ef við þurfum að skipta út eða breyta tilteknum stöfum í texta getum við notað skipunina tr (stytting á translate) eins og í eftirfarandi dæmi:

echo "Halló" | tr '[:lower:]' '[:upper:]'
echo "a,b,c" | tr ',' '\n'
sem annaðhvort breyta textanum í hástafi eða skipta út kommum fyrir nýjar línur.

sed: einföld textabreyting

Skipunin sed (stytting á stream editor) er sérstaklega hönnuð til að eiga við textastrauma og með keyrslu á borð við

echo "Halló heimur" | sed 's/heimur/Linux/'
getum við skipt út orðinu heimur fyrir Linux á fljótlegan hátt.

awk: vinna með dálka

Þegar vinna þarf með flóknara dálka- eða línuskipulag er gott að keyra skipunina awk (nefnd eftir höfundum sínum Aho, Weinberger og Kernighan) eins og í eftirfarandi dæmi:

awk '{print $1}' logs/access.log
awk -F: '{print $1, $7}' /etc/passwd
þar sem awk vinnur með hvern dálk fyrir sig. Sjálfgefið notar það bil sem skilju, en með fánanum -F: getum við breytt því í tvípunkt.

Prófaðu einnig að vinna með CSV-skrána okkar með því að keyra

awk -F, '{print $1, $3}' data/scores.csv
sem sýnir okkur völdu dálkana á skipulegan hátt.

xargs: nota lista sem viðföng

Þegar við viljum breyta lista yfir skrár yfir í viðföng fyrir aðra skipun getum við notað skipunina xargs (stytting á extended arguments) og keyrt:

find . -name "*.txt" | xargs wc -l
þar sem find finnur skrárnar og xargs sendir þær áfram til línutalningar.

Skráarnöfn geta innihaldið bil

Þegar við notum find með xargs er öruggara að nota núllstaf sem skilju með skipuninni

find . -name "*.txt" -print0 | xargs -0 wc -l
til að tryggja að skráarnöfn með bilum eða sértáknum valdi ekki vandamálum.


Raunverulegt dæmi: greina textaskrá

Segjum að við séum með logs/access.log skrá með mörgum línum og markmið okkar sé að finna þær 5 IP-tölur sem koma oftast fyrir í fyrsta dálki skráarinnar. Til þess getum við skeytt saman mörgum tólum og keyrt flókna keðju á borð við

cut -d' ' -f1 logs/access.log | sort | uniq -c | sort -nr | head -n 5
sem leysir verkefnið á örfáum sekúndum.

Í þessari skipun fylgjum við þessum skrefum:

  1. cut -d' ' -f1: klippir út fyrsta dálkinn þar sem IP-talan er að finna.
  2. sort: raðar öllum línum saman svo hægt sé að telja þær.
  3. uniq -c: telur nákvæmlega hve oft hver IP-tala kemur fyrir.
  4. sort -nr: raðar niðurstöðunum tölulega þannig að stærsta talan komi fyrst.
  5. head -n 5: síar út og sýnir okkur einungis efstu 5 línurnar.

Prófaðu sjálf/ur

Hvernig myndirðu telja hversu margar einstakar línur eru í data/names.txt?

Ein lausn

Við getum raðað og eytt endurtekningum áður en við teljum með því að keyra

sort data/names.txt | uniq | wc -l
sem skilar okkur nákvæmum fjölda einstakra nafna.

Prófaðu: algengasti liturinn

Hvaða litur kemur oftast fyrir í data/colors.txt?

Lausn

Við getum raðað litunum og síað þann vinsælasta út með því að keyra

sort data/colors.txt | uniq -c | sort -nr | head -n 1
sem sýnir okkur algengasta litinn ásamt fjölda skipta.

Prófaðu: hæstu stigin

Sýndu þrjár hæstu línurnar í data/scores.csv eftir stigum. Sleppum hauslínunni fyrst.

Lausn

Við getum beitt tail og sort saman og keyrt

tail -n +2 data/scores.csv | sort -t, -k3 -nr | head -n 3
til að fá þá þrjá einstaklinga sem náðu hæstum árangri.

Prófaðu: loggskrá í færibandi

Finndu þrjár algengustu vefslóðirnar í logs/access.log. Vefslóðin er sjöundi dálkurinn í skránni.

Lausn

Til þess að sía út sjöunda dálkinn og telja hann getum við keyrt skipunina

cut -d' ' -f7 logs/access.log | sort | uniq -c | sort -nr | head -n 3
sem birtir fljótt þær slóðir sem fengu flestar heimsóknir.

Vissir þú?

Pípur komu inn í Unix árið 1973. Hugmyndin var svo góð að hún breytti því hvernig fólk hannaði skipanalínuforrit: forrit þurftu ekki lengur að gera allt sjálf, heldur bara tala skýrt við næsta forrit í röðinni.

Smá samantekt

Eftir þennan hluta ættirðu að geta:

  • útskýrt muninn á stdin, stdout og stderr,
  • notað >, >>, <, 2> og 2>&1,
  • tengt skipanir saman með |,
  • skilið af hverju mörg forrit lesa úr skrá eða úr staðalinntaki,
  • notað sort, uniq, cut, wc, tee, tr, sed, awk og xargs í einföldum dæmum,
  • áttað þig á af hverju litir hverfa stundum þegar úttak fer í pípu.