Hvad er stdin, stdout og stderr på Linux?

stdin, stdout og stderr er tre datastrømme, der oprettes, når du starter en Linux-kommando. Du kan bruge dem til at fortælle, om dine scripts sendes eller omdirigeres. Vi viser dig hvordan.

Streams forbinder to punkter

Så snart du begynder at lære om Linux og Unix-lignende operativsystemer, vil du støde på begreberne stdin, stdout og stederr. Disse er tre standardstrømme der etableres, når en Linux-kommando udføres. Inden for databehandling er en strøm noget, der kan overføre data. I tilfælde af disse strømme er disse data tekst.

Datastrømme har ligesom vandstrømme to ender. De har en kilde og en udstrømning. Uanset hvilken Linux-kommando du bruger giver den ene ende af hver stream. Den anden ende bestemmes af den shell, der lancerede kommandoen. Denne ende vil blive forbundet til terminalvinduet, forbundet til et rør eller omdirigeret til en fil eller anden kommando i henhold til den kommandolinje, der lancerede kommandoen.

Linux Standard Streams

I Linux er stdin standardinputstrømmen. Dette accepterer tekst som input. Tekstoutput fra kommandoen til shellen leveres via stdout-strømmen (standard ud). Fejlmeddelelser fra kommandoen sendes gennem stderr-strømmen (standardfejl).

Så du kan se, at der er to output-streams, stdout og stderr, og en input-stream, stdin. Fordi fejlmeddelelser og normal output hver har deres egen kanal til at føre dem til terminalvinduet, kan de håndteres uafhængigt af hinanden.

Streams håndteres som filer

Streams i Linux – som næsten alt andet – behandles som om de var filer. Du kan læse tekst fra en fil, og du kan skrive tekst ind i en fil. Begge disse handlinger involverer en strøm af data. Så konceptet med at håndtere en strøm af data som en fil er ikke så meget af en strækning.

Hver fil, der er knyttet til en proces, tildeles et unikt nummer for at identificere den. Dette er kendt som filbeskrivelsen. Når en handling skal udføres på en fil, filbeskrivelsen bruges til at identificere filen.

Disse værdier bruges altid til stdin, stdout og stderr:

0: stdin
1: standout
2: stderr

Reagerer på rør og omdirigeringer

For at lette nogens introduktion til et emne er en almindelig teknik at undervise i en forenklet version af emnet. For eksempel med grammatik får vi at vide, at reglen er “I før E, undtagen efter C.” Men faktisk der er flere undtagelser fra denne regel end der er tilfælde, der adlyder det.

  Sådan forvandler du din Raspberry Pi til en Linux NAS

På samme måde, når man taler om stdin, stdout og stderr, er det praktisk at tro det accepterede aksiom, at en proces hverken ved eller bekymrer sig om, hvor dens tre standardstrømme afsluttes. Skal en proces bekymre sig om dens output går til terminalen eller bliver omdirigeret til en fil? Kan den overhovedet se, om dens input kommer fra tastaturet eller bliver ledt ind i det fra en anden proces?

Faktisk ved en proces – eller i det mindste kan den finde ud af det, hvis den vælger at tjekke – og den kan ændre sin adfærd i overensstemmelse hermed, hvis softwareforfatteren besluttede at tilføje denne funktionalitet.

Vi kan meget let se denne ændring i adfærd. Prøv disse to kommandoer:

ls

ls | cat

ls-kommandoen opfører sig anderledes, hvis dens output (stdout) overføres til en anden kommando. Det er ls der skifter til en enkelt kolonne output, det er ikke en konvertering udført af cat. Og ls gør det samme, hvis dets output bliver omdirigeret:

ls > capture.txt

ls > capture.txt i et terminalvindue” 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

Der er en fordel ved at have fejlmeddelelser leveret af en dedikeret stream. Det betyder, at vi kan omdirigere en kommandos output (stdout) til en fil og stadig se eventuelle fejlmeddelelser (stderr) i terminalvinduet. Du kan reagere på fejlene, hvis du har brug for det, efterhånden som de opstår. Det forhindrer også fejlmeddelelserne i at forurene filen, som stdout er blevet omdirigeret til.

Indtast følgende tekst i en editor og gem den i en fil kaldet error.sh.

#!/bin/bash

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

Gør scriptet eksekverbart med denne kommando:

chmod +x error.sh

Den første linje i scriptet ekko tekst til terminalvinduet via stdout-strømmen. Den anden linje forsøger at få adgang til en fil, der ikke eksisterer. Dette vil generere en fejlmeddelelse, der leveres via stderr.

Kør scriptet med denne kommando:

./error.sh

Vi kan se, at begge strømme af output, stdout og stderr, er blevet vist i terminalvinduerne.

Lad os prøve at omdirigere outputtet til en fil:

./error.sh > capture.txt

./error.sh > capture.txt i et terminalvindue” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Fejlmeddelelsen, der leveres via stderr, sendes stadig til terminalvinduet.  Vi kan kontrollere indholdet af filen for at se, om stdout-outputtet gik til filen.</p>
<pre>cat capture.txt</pre>
<p><img loading=

Outputtet fra stdin blev omdirigeret til filen som forventet.

> omdirigeringssymbolet fungerer som standard med stdout. Du kan bruge en af ​​de numeriske filbeskrivelser til at angive, hvilken standard outputstrøm du ønsker at omdirigere.

  5 bedste Linux-distributioner for bedre batterilevetid

For eksplicit at omdirigere stdout, brug denne omdirigeringsinstruktion:

1>

For eksplicit at omdirigere stderr, brug denne omdirigeringsinstruktion:

2>

Lad os prøve vores test igen, og denne gang bruger vi 2>:

./error.sh 2> capture.txt

./error.sh 2> capture.txt i et terminalvindue” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Fejlmeddelelsen omdirigeres, og stdout-ekkomeddelelsen sendes til terminalvinduet:</p>
<p ><img klasse=

Stderr-meddelelsen er i capture.txt som forventet.

Omdirigerer Både stdout og stderr

Hvis vi kan omdirigere enten stdout eller stderr til en fil uafhængigt af hinanden, burde vi vel være i stand til at omdirigere dem begge på samme tid til to forskellige filer?

Ja vi kan. Denne kommando vil dirigere stdout til en fil kaldet capture.txt og stderr til en fil kaldet error.txt.

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

./error.sh 1> capture.txt 2> error.txt i et terminalvindue” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Fordi begge strømme af output – standardoutput og standardfejl – omdirigeres til filer, er der ikke noget synligt output i terminalvinduet.  Vi vender tilbage til kommandolinjeprompten, som om intet er sket.</p>
<p><img loading=

Lad os tjekke indholdet af hver fil:

cat capture.txt
cat error.txt

Omdirigerer stdout og stderr til den samme fil

Det er pænt, vi har fået hver af standard output-streams til at gå til sin egen dedikerede fil. Den eneste anden kombination, vi kan gøre, er at sende både stdout og stderr til den samme fil.

Vi kan opnå dette med følgende kommando:

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

Lad os bryde det ned.

./error.sh: Starter scriptfilen error.sh.
> capture.txt: Omdirigerer stdout-strømmen til capture.txt-filen. > er en forkortelse for 1>.
2>&1: Dette bruger &> omdirigeringsinstruktionen. Denne instruktion giver dig mulighed for at fortælle skallen at få en strøm til at nå samme destination som en anden strøm. I dette tilfælde siger vi “omdiriger stream 2, stderr, til den samme destination, som stream 1, stdout, bliver omdirigeret til.”

./error.sh > capture.txt 2&>1 i et terminalvindue” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Der er intet synligt output.  Det er opmuntrende.</p>
<p><img loading=

Lad os tjekke capture.txt-filen og se, hvad der er i den.

cat capture.txt

Både stdout- og stderr-strømmene er blevet omdirigeret til en enkelt destinationsfil.

For at få outputtet fra en stream omdirigeret og stille smidt væk, skal du rette outputtet til /dev/null.

Registrering af omdirigering i et script

Vi diskuterede, hvordan en kommando kan registrere, om nogen af ​​strømmene bliver omdirigeret, og kan vælge at ændre dens adfærd i overensstemmelse hermed. Kan vi opnå dette i vores egne scripts? Ja vi kan. Og det er en meget nem teknik at forstå og anvende.

Indtast følgende tekst i en editor og gem 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

Brug følgende kommando for at gøre det eksekverbart:

chmod +x input.sh

Den smarte del er test inden for de firkantede parenteser. Indstillingen -t (terminal) returnerer sand (0), hvis den fil, der er knyttet til filbeskrivelsen afsluttes i terminalvinduet. Vi har brugt filbeskrivelsen 0 som argumentet til testen, som repræsenterer stdin.

  Sådan opsætter du et Linux Server Dashboard med Linux Dash

Hvis stdin er forbundet til et terminalvindue, vil testen vise sig at være sand. Hvis stdin er forbundet til en fil eller et rør, vil testen mislykkes.

Vi kan bruge enhver praktisk tekstfil til at generere input til scriptet. Her bruger vi en kaldet 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

Scriptet genkender, at dets input overføres til det. Eller mere præcist genkender den endnu en gang, at stdin-strømmen ikke er forbundet til et terminalvindue.

Lad os køre scriptet uden hverken pipes eller omdirigeringer.

./input.sh

Stdin-strømmen er forbundet til terminalvinduet, og scriptet rapporterer dette i overensstemmelse hermed.

For at kontrollere det samme med outputstrømmen, har vi brug for et nyt script. Indtast følgende i en editor og gem det 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

Brug følgende kommando for at gøre det eksekverbart:

chmod +x input.sh

Den eneste væsentlige ændring af dette script er i testen i de firkantede parenteser. Vi bruger tallet 1 til at repræsentere filbeskrivelsen for stdout.

Lad os prøve det. Vi sender udgangen gennem kat.

./output | cat

Scriptet genkender, at dets output ikke går direkte til et terminalvindue.

Vi kan også teste scriptet ved at omdirigere outputtet til en fil.

./output.sh > capture.txt

Der er intet output til terminalvinduet, vi vender lydløst tilbage til kommandoprompten. Som vi kunne forvente.

Vi kan se inde i capture.txt-filen for at se, hvad der blev fanget. Brug følgende kommando til at gøre det.

cat capture.sh

Igen, den simple test i vores script registrerer, at stdout-strømmen ikke sendes direkte til et terminalvindue.

Hvis vi kører scriptet uden pipes eller omdirigeringer, burde det registrere, at stdout bliver leveret direkte til terminalvinduet.

./output.sh

Og det er præcis, hvad vi ser.

Bevidsthedsstrømme

At vide, hvordan man kan se, om dine scripts er forbundet til terminalvinduet, eller et rør, eller bliver omdirigeret, giver dig mulighed for at justere deres adfærd i overensstemmelse hermed.

Logning og diagnostisk output kan være mere eller mindre detaljeret, afhængigt af om det går til skærmen eller til en fil. Fejlmeddelelser kan logges til en anden fil end den normale programoutput.

Som det normalt er tilfældet, giver mere viden flere muligheder.