Master stdin, stdout & stderr på Linux: En komplett guide

Ved oppstart av en Linux-kommando etableres tre datastrømmer: stdin, stdout og stderr. Disse strømmene er avgjørende for hvordan skript kommuniserer med omgivelsene og hvordan data flyter inn og ut av prosesser. La oss utforske hvordan de fungerer.

Forbindelsespunkt for datastrømmer

Innenfor Linux og andre Unix-lignende systemer er stdin, stdout og stderr standardiserte strømmer som opprettes når en kommando kjøres. En datastrøm er enkelt sagt en kanal for dataoverføring. I dette tilfellet er dataene formatert som tekst.

Strømmer kan sammenlignes med elver, med en kilde og et utløp. For hver Linux-kommando defineres kilden for strømmen av selve kommandoen. Utløpet derimot, bestemmes av skallet som startet kommandoen. Dette utløpet kan være tilkoblet terminalvinduet, en rørledning (pipe), en fil eller til og med en annen kommando, avhengig av instruksjonene gitt i kommandolinjen.

De standardiserte strømmene i Linux

I Linux fungerer stdin som standard inngangsstrøm, som aksepterer tekst som input. Kommandoens tekstutdata sendes via stdout (standard utgangsstrøm). Feilmeldinger fra kommandoen dirigeres gjennom stderr (standard feilstrøm).

Dette betyr at det finnes to separate utgangsstrømmer: stdout for vanlig utdata og stderr for feilmeldinger. Denne separasjonen gjør det mulig å behandle hver type utdata uavhengig av hverandre.

Strømmer som filer

I Linux behandles strømmer i praksis som filer. Du kan lese tekst fra en fil, og skrive tekst til en fil. Begge disse handlingene involverer en strøm av data. Dette gjør det enkelt å håndtere en datastrøm som en fil.

Hver fil tilknyttet en prosess identifiseres med et unikt nummer, kjent som en filbeskrivelse. Denne beskrivelsen brukes når en handling skal utføres på filen. For stdin, stdout og stderr er disse verdiene alltid:

0: stdin
1: stdout
2: stderr

Strømmenes reaksjon på rør og omdirigering

Ofte lærer man en forenklet versjon av et tema for å lette introduksjonen. Men som for eksempel i grammatikk, hvor det finnes unntak til regler, er det også tilfeller der strømmene avviker fra sin antatte oppførsel.

Det antas ofte at prosesser ikke vet eller bryr seg om hvor strømmene ender opp. Men prosesser kan faktisk detektere hvor strømmene går, og de kan endre oppførsel avhengig av dette.

Dette kan vi illustrere med følgende to kommandoer:

ls

ls | cat

Når `ls` kommandoens utdata sendes til en annen kommando via en rørledning, endrer `ls` utdataformatet til en enkelt kolonne. Dette er ikke noe som utføres av `cat`. Det samme skjer hvis `ls` utdata omdirigeres til en fil:

ls > capture.txt

Omdirigering av stdout og stderr

Den separate håndteringen av feilmeldinger er nyttig, fordi det lar deg omdirigere en kommandos normale utdata til en fil, mens feilmeldinger fortsatt vises i terminalen. Dette gjør det mulig å håndtere feil fortløpende og holder feilmeldinger separate fra den omdirigerte utdataen.

Lag en fil ved navn «error.sh» med følgende innhold:

#!/bin/bash

echo "About to try to access a file that doesn't exist"
cat filename.txt

Gjør skriptet kjørbart:

chmod +x error.sh

Skriptets første linje skriver ut tekst til terminalen via stdout. Den andre linjen prøver å lese en fil som ikke eksisterer, som resulterer i en feilmelding via stderr.

Kjør skriptet:

./error.sh

Både standard utdata og feilmeldinger vises i terminalvinduet.

Omdiriger stdout til en fil:

./error.sh > capture.txt

Som forventet finnes standard utdata i filen.

Omdirigeringssymbolet `>` gjelder stdout som standard, men du kan spesifisere hvilken strøm du ønsker å omdirigere med de numeriske filbeskrivelsene:

For eksplisitt omdirigering av stdout:

1>

For eksplisitt omdirigering av stderr:

2>

Prøv igjen, denne gang med `2>`:

./error.sh 2> capture.txt

Feilmeldingen er nå i capture.txt-filen.

Omdirigering av stdout og stderr til separate filer

Vi kan omdirigere stdout og stderr uavhengig, og vi kan også omdirigere dem samtidig til to separate filer. Følgende kommando dirigerer stdout til «capture.txt» og stderr til «error.txt»:

./error.sh 1> capture.txt 2> error.txt

Sjekk innholdet i hver fil:

cat capture.txt
cat error.txt

Omdirigering av stdout og stderr til samme fil

Vi kan også sende både stdout og stderr til samme fil. Følgende kommando gjør dette:

./error.sh > capture.txt 2>&1

La oss gå gjennom den:

`./error.sh` starter skriptet. `> capture.txt` dirigerer stdout (forkortelse for `1>`) til filen «capture.txt». `2>&1` dirigerer stderr (strøm 2) til samme sted som stdout (strøm 1), det vil si til «capture.txt».

cat capture.txt

Både stdout og stderr er omdirigert til den samme filen. For å kaste bort utdata kan du omdirigere det til `/dev/null`.

Oppdage omdirigering i et skript

En kommando kan detektere om strømmer omdirigeres. Dette kan også gjøres i skript. Lag en fil ved navn «input.sh» med følgende innhold:

#!/bin/bash

if [ -t 0 ]; then

  echo stdin coming from keyboard

else

  echo stdin coming from a pipe or a file

fi

Gjør skriptet kjørbart:

chmod +x input.sh

Testen `-t` i hakeparentesene returnerer sant dersom filen tilknyttet filbeskrivelsen ender i terminalvinduet. Vi bruker `0` som argument for testen, som representerer stdin. Hvis stdin er koblet til et terminalvindu vil testen lykkes, ellers mislykkes den.

Bruk en testfil `dummy.txt`:

./input.sh

Skriptet gjenkjenner at inndata ikke kommer fra tastaturet, men fra en fil. Skriptets oppførsel kan justeres i henhold til dette.

Test med en rørledning:

cat dummy.txt | ./input.sh

Skriptet gjenkjenner at inndata overføres via en rørledning, og ikke er tilkoblet et terminalvindu.

Kjør skriptet uten rør eller omdirigering:

./input.sh

Skriptet gjenkjenner at stdin er koblet direkte til terminalen. For å sjekke det samme med utdatastrømmen, lag en ny fil med navn «output.sh»:

#!/bin/bash

if [ -t 1 ]; then

echo stdout is going to the terminal window

else

echo stdout is being redirected or piped

fi

Gjør den kjørbar:

chmod +x input.sh

Den eneste endringen er i testen, hvor vi bruker `1` for filbeskrivelsen til stdout.

Test den. Send utdataen gjennom `cat`:

./output | cat

Skriptet gjenkjenner at utdata ikke går direkte til et terminalvindu.

Test med å omdirigere utdataen til en fil:

./output.sh > capture.txt

Ingen utdata vises i terminalen.

Sjekk filinnholdet:

cat capture.sh

Testen i skriptet gjenkjenner at stdout ikke går direkte til et terminalvindu. Kjør skriptet uten rør eller omdirigering:

./output.sh

Skriptet viser at stdout leveres direkte til terminalvinduet.

Strømmenes bevissthet

Ved å vite om skript er koblet til et terminalvindu, en rørledning eller er omdirigert, kan oppførselen justeres deretter.

Loggføring og diagnostisk utdata kan være mer eller mindre detaljert, avhengig av om det går til skjermen eller til en fil. Feilmeldinger kan logges til en annen fil enn den vanlige programutdataen.

Mer kunnskap gir som oftest flere muligheter.