Hva er stdin, stdout og stderr på Linux?

stdin, stdout og stderr er tre datastrømmer som opprettes når du starter en Linux-kommando. Du kan bruke dem til å fortelle om skriptene dine sendes eller omdirigeres. Vi viser deg hvordan.

Strømmer slå sammen to punkter

Så snart du begynner å lære om Linux og Unix-lignende operativsystemer, vil du komme over begrepene stdin, stdout og stederr. Disse er tre standardstrømmer som opprettes når en Linux-kommando utføres. I databehandling er en strøm noe som kan overføre data. Når det gjelder disse strømmene, er disse dataene tekst.

Datastrømmer, som vannstrømmer, har to ender. De har en kilde og en utstrømning. Uansett hvilken Linux-kommando du bruker gir den ene enden av hver strøm. Den andre enden bestemmes av skallet som startet kommandoen. Den enden vil bli koblet til terminalvinduet, koblet til et rør eller omdirigert til en fil eller annen kommando, i henhold til kommandolinjen som startet kommandoen.

Linux Standard Streams

I Linux er stdin standard inngangsstrøm. Dette godtar tekst som input. Tekstutdata fra kommandoen til skallet leveres via stdout-strømmen (standard ut). Feilmeldinger fra kommandoen sendes gjennom stderr-strømmen (standardfeil).

Så du kan se at det er to utgangsstrømmer, stdout og stderr, og en inngangsstrøm, stdin. Fordi feilmeldinger og normal utgang hver har sin egen kanal for å føre dem til terminalvinduet, kan de håndteres uavhengig av hverandre.

Strømmer håndteres som filer

Strømmer i Linux – som nesten alt annet – behandles som om de var filer. Du kan lese tekst fra en fil, og du kan skrive tekst inn i en fil. Begge disse handlingene involverer en strøm av data. Så konseptet med å håndtere en strøm av data som en fil er ikke så langvarig.

Hver fil knyttet til en prosess er tildelt et unikt nummer for å identifisere den. Dette er kjent som filbeskrivelsen. Når det er nødvendig å utføre en handling på en fil, filbeskrivelsen brukes til å identifisere filen.

Disse verdiene brukes alltid for stdin, stdout og stderr:

0: stdin
1: standout
2: stderr

Reagere på rør og omdirigeringer

For å lette noens introduksjon til et emne, er en vanlig teknikk å undervise i en forenklet versjon av emnet. For eksempel, med grammatikk, blir vi fortalt at regelen er «I før E, bortsett fra etter C.» Men faktisk der er flere unntak fra denne regelen enn det er tilfeller som adlyder det.

  Windows 10 lar deg laste inn en tilpasset Linux-kjerne

På samme måte, når man snakker om stdin, stdout og stderr, er det praktisk å tro ut det aksepterte aksiomet at en prosess verken vet eller bryr seg om hvor de tre standardstrømmene avsluttes. Bør en prosess bry seg om utdataene går til terminalen eller omdirigeres til en fil? Kan den til og med fortelle om inndataene kommer fra tastaturet eller sendes inn i det fra en annen prosess?

Faktisk vet en prosess – eller i det minste kan den finne ut, hvis den velger å sjekke – og den kan endre oppførselen tilsvarende hvis programvareforfatteren bestemte seg for å legge til denne funksjonaliteten.

Vi kan se denne endringen i atferd veldig lett. Prøv disse to kommandoene:

ls

ls | cat

ls-kommandoen oppfører seg annerledes hvis utgangen (stdout) blir overført til en annen kommando. Det er ls som bytter til en enkelt kolonneutgang, det er ikke en konvertering utført av cat. Og ls gjør det samme hvis utgangen blir omdirigert:

ls > capture.txt

ls > capture.txt i et terminalvindu” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<pre>cat capture.txt</pre>
<p><img loading=

Omdirigerer stdout og stderr

Det er en fordel å ha feilmeldinger levert av en dedikert strøm. Det betyr at vi kan omdirigere en kommandos utdata (stdout) til en fil og fortsatt se eventuelle feilmeldinger (stderr) i terminalvinduet. Du kan reagere på feilene hvis du trenger det, ettersom de oppstår. Det stopper også feilmeldingene fra å forurense filen som stdout har blitt omdirigert til.

Skriv inn følgende tekst i en editor og lagre den i en fil som heter error.sh.

#!/bin/bash

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

Gjør skriptet kjørbart med denne kommandoen:

chmod +x error.sh

Den første linjen i skriptet ekko tekst til terminalvinduet, via stdout-strømmen. Den andre linjen prøver å få tilgang til en fil som ikke eksisterer. Dette vil generere en feilmelding som leveres via stderr.

Kjør skriptet med denne kommandoen:

./error.sh

Vi kan se at begge utdatastrømmene, stdout og stderr, har blitt vist i terminalvinduene.

La oss prøve å omdirigere utdataene til en fil:

./error.sh > capture.txt

./error.sh > capture.txt i et terminalvindu” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Feilmeldingen som leveres via stderr sendes fortsatt til terminalvinduet.  Vi kan sjekke innholdet i filen for å se om stdout-utgangen gikk til filen.</p>
<pre>cat capture.txt</pre>
<p><img loading=

Utdataene fra stdin ble omdirigert til filen som forventet.

> omdirigeringssymbolet fungerer med stdout som standard. Du kan bruke en av de numeriske filbeskrivelsene for å indikere hvilken standard utdatastrøm du ønsker å omdirigere.

  Få sunne påminnelser på Linux-skrivebordet ved å bruke Stretchly

For å eksplisitt omdirigere stdout, bruk denne omdirigeringsinstruksjonen:

1>

For å eksplisitt omdirigere stderr, bruk denne omdirigeringsinstruksjonen:

2>

La oss prøve på nytt, og denne gangen bruker vi 2>:

./error.sh 2> capture.txt

./error.sh 2> capture.txt i et terminalvindu” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Feilmeldingen blir omdirigert og standard ekkomeldingen sendes til terminalvinduet:</p>
<p ><img klasse=

Stderr-meldingen er i capture.txt som forventet.

Omdirigerer Både stdout og stderr

Sikkert, hvis vi kan omdirigere enten stdout eller stderr til en fil uavhengig av hverandre, burde vi være i stand til å omdirigere dem begge samtidig, til to forskjellige filer?

Ja vi kan. Denne kommandoen vil lede stdout til en fil kalt capture.txt og stderr til en fil kalt error.txt.

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

./error.sh 1> capture.txt 2> error.txt i et terminalvindu” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Fordi begge utdatastrømmene – standardutdata og standardfeil – blir omdirigert til filer, er det ingen synlig utdata i terminalvinduet.  Vi returneres til ledeteksten som om ingenting har skjedd.</p>
<p><img loading=

La oss sjekke innholdet i hver fil:

cat capture.txt
cat error.txt

Omdirigerer stdout og stderr til samme fil

Det er greit, vi har fått hver av standard utdatastrømmene til sin egen dedikerte fil. Den eneste andre kombinasjonen vi kan gjøre er å sende både stdout og stderr til samme fil.

Vi kan oppnå dette med følgende kommando:

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

La oss bryte det ned.

./error.sh: Starter skriptfilen error.sh.
> capture.txt: Omdirigerer stdout-strømmen til capture.txt-filen. > er en forkortelse for 1>.
2>&1: Dette bruker &> omdirigeringsinstruksjonen. Denne instruksjonen lar deg fortelle skallet å få en strøm til å komme til samme destinasjon som en annen strøm. I dette tilfellet sier vi «omdiriger strøm 2, stderr, til samme destinasjon som strøm 1, stdout, blir omdirigert til.»

./error.sh > capture.txt 2&>1 i et terminalvindu” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Det er ingen synlig utgang.  Det er oppmuntrende.</p>
<p><img loading=

La oss sjekke capture.txt-filen og se hva som er i den.

cat capture.txt

Både stdout- og stderr-strømmene har blitt omdirigert til en enkelt destinasjonsfil.

For å få utdataene fra en strøm omdirigert og stille kastet bort, diriger utdataene til /dev/null.

Oppdager omdirigering i et skript

Vi diskuterte hvordan en kommando kan oppdage om noen av strømmene blir omdirigert, og kan velge å endre oppførselen deretter. Kan vi oppnå dette i våre egne manus? Ja vi kan. Og det er en veldig enkel teknikk å forstå og bruke.

Skriv inn følgende tekst i en editor og lagre den som input.sh.

#!/bin/bash

if [ -t 0 ]; then

  echo stdin coming from keyboard
 
else

  echo stdin coming from a pipe or a file
 
fi

Bruk følgende kommando for å gjøre den kjørbar:

chmod +x input.sh

Den smarte delen er test innenfor de firkantede parentesene. Alternativet -t (terminal) returnerer sann (0) hvis filen assosiert med filbeskrivelsen avsluttes i terminalvinduet. Vi har brukt filbeskrivelsen 0 som argument for testen, som representerer stdin.

  Hvordan slå sammen PDF-er med PDFSam på Linux

Hvis stdin er koblet til et terminalvindu, vil testen vise seg å være sann. Hvis stdin er koblet til en fil eller et rør, vil testen mislykkes.

Vi kan bruke hvilken som helst praktisk tekstfil for å generere input til skriptet. Her bruker vi en som heter dummy.txt.

./input.sh 

The output shows that the script recognizes that the input isn’t coming from a keyboard, it is coming from a file. If you chose to, you could vary your script’s behavior accordingly.

That was with a file redirection, let’s try it with a pipe.

cat dummy.txt | ./input.sh

Skriptet gjenkjenner at inndata blir overført til det. Eller mer presist, den gjenkjenner igjen at stdin-strømmen ikke er koblet til et terminalvindu.

La oss kjøre skriptet med verken pipes eller omdirigeringer.

./input.sh

Stdin-strømmen er koblet til terminalvinduet, og skriptet rapporterer dette deretter.

For å sjekke det samme med utdatastrømmen, trenger vi et nytt skript. Skriv inn følgende i en editor og lagre den som 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

Bruk følgende kommando for å gjøre den kjørbar:

chmod +x input.sh

Den eneste vesentlige endringen til dette skriptet er i testen i hakeparentesene. Vi bruker sifferet 1 for å representere filbeskrivelsen for stdout.

La oss prøve det. Vi sender utgangen gjennom katten.

./output | cat

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

Vi kan også teste skriptet ved å omdirigere utdataene til en fil.

./output.sh > capture.txt

Det er ingen utgang til terminalvinduet, vi blir stille tilbake til ledeteksten. Som vi forventer.

Vi kan se inne i capture.txt-filen for å se hva som ble fanget. Bruk følgende kommando for å gjøre det.

cat capture.sh

Igjen, den enkle testen i skriptet vårt oppdager at stdout-strømmen ikke sendes direkte til et terminalvindu.

Hvis vi kjører skriptet uten pipes eller omdirigeringer, bør det oppdage at stdout blir levert direkte til terminalvinduet.

./output.sh

Og det er akkurat det vi ser.

Strømmer av bevissthet

Å vite hvordan du kan finne ut om skriptene dine er koblet til terminalvinduet, eller et rør, eller blir omdirigert, lar deg justere oppførselen deres deretter.

Logging 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 programutgangen.

Som vanligvis er tilfellet, gir mer kunnskap flere alternativer.