Linux værktøjer røradfærd: Er det en fejl eller en funktion?

Denne guide forklarer, hvordan pipes i Linux fungerer, og hvorfor visse programmer ændrer deres outputformat, når de pipedes, for at sikre korrekt datahåndtering.
Hvis du har erfaring med Linux kommandolinjen, har du sikkert brugt en pipe til at løse opgaver ved at kombinere simple programmer. Det er UNIX-måden.
En pipe forbinder en programs outputstream med en andens input, men der kan være mere på spil bag kulisserne, end hvad øjet ser.
Hvorfor har nogle programmer forskellig output, når de pipedes?
Tag et kig på ls, en af de mest almindelige og nyttige kommandoer, der findes. Du kender sikkert til, hvordan det fungerer:
Kører du ls uden argumenter og uden særlig konfiguration, får du en liste over filer i den nuværende mappe i multikolonneformat. Men se, hvad der sker, når du pipeder ls:
Her bruger jeg cat til at demonstrere effekten af pipede ls-output. Du kan også sende output fra ls til en fil ved at bruge omdirigering, med en kommando som ls > outputfile.
Det er ikke kun ls, der gør dette, så hvorfor er en sådan funktion almindelig blandt Linux-programmer? Det viser sig, at særlig håndtering af pipet output kan være nyttig af flere årsager.
I tilfælde af ls og andre værktøjer, der producerer formateret output, giver det mening at forenkle det output, når det pipedes. Kommandoen, du pipeder til, vil forvente input i et linje-for-linjes format, som følger den almindelige Unix-konvention for linjeorienterede værktøjer. Hvis ls sendte sit kolonnebaserede output til andre programmer, ville de finde det besværligt, hvis ikke umuligt, at parse korrekt.
Nogle programmer, især nyere, formaterer deres normale output endnu mere, ved at bruge ANSI-sekvenser til at farve eller kursivere tekst. Igen ville sådan tekst være kompliceret at parse for andre værktøjer, og alt ekstra arbejde, der er nødvendigt for blot at håndtere input, er uønsket.
Og hvordan gør de det?
Når du kører et program, sender din shell det filbeskrivelser for standard input, output og fejlstreams. Typisk er disse forbundet til din terminal, så de taster, du trykker på, ankommer via standard input, og programmets output vises på din skærm. Du kan dog sende disse streams et andet sted hen, via pipes eller filomdirigering.
Det meste af tiden vil et program ikke bekymre sig om disse detaljer. Hvis input kommer fra dit tastatur eller en anden proces, vil et værktøj som grep behandle dem identisk. Dette giver os meget kraftfulde værktøjer, som vi kan kombinere på forskellige måder. Men som med eksemplet med ls ovenfor, kan et program lejlighedsvis have brug for at vide, om en input- eller outputstream er forbundet til terminalen eller noget andet. Til det findes C-biblioteksfunktionen isatty:
#include <unistd.h> int isatty(int fd); Denne funktion tager et heltal, der repræsenterer en filbeskrivelse, og returnerer 1, hvis det refererer til en terminal, 0 ellers. Filbeskrivelsen kan være hvilket som helst heltal, men værdierne 0, 1 og 2 er reserveret til stdin, stdout og stderr, henholdsvis.
Der er et højere niveau svar for dig at bruge i shell-scripts: -t test. Dette er et meget tæt svar på isatty-funktionen:
#!/bin/bash if test -t 0; then echo "standard input er en terminal" else echo "standard input er ikke en terminal" fi Programmet opfører sig præcist som du håbede og forventede:
Nogle eksempel pipe-bevidste kommandoer
Som nævnt ovenfor fungerer ls forskelligt, når det pipedes, og opfører sig grundlæggende som om -1 valgmuligheden var blevet givet. Hvis du af en eller anden grund ønsker at overskrive denne adfærd, skal du blot bruge -C valgmuligheden:
Ps-kommandoen giver information om kørende processer, inklusive kommandoen, der startede hver proces. Men da kommandoer kan være meget lange, vil programmet forkorte den fulde kommando for at passe ind i din terminal:
Når du pipeder ps-output til en fil, er der dog ingen grund til denne forkortelse, så programmet udskriver fulde kommandoer:
Grep er et kraftfuldt værktøj, der lader dig søge i filer efter regulære udtryksmønstre. Dets farvevalgmulighed fremhæver matcher passende:
Men når det output omdirigeres, gør grep det fornuftige og stopper med at producere de specielle tegnsekvenser, der styrer disse farver. Ellers - og du kan teste dette med grep --color=always - kan du ende med en fil, der ser sådan ud:
Endelig er curl en af de mest interessante anvendelser af output stream-detektion. Når du sender det en URL, vil programmet udskrive.
Men hvis du omdirigerer den output til en fil, gør curl noget bedre end blot at forblive stille:
Selvom du ikke kan se det i det skærmbillede, viser curl en dynamisk fremdriftsmåler, der opdateres, når din anmodning downloades. Det er ikke så nyttigt for en lille webside, men for større svar, herunder store filnedlastninger, kan denne output være ret nyttig. Hvordan gør curl dette, mens den stadig omdirigerer din output til filen? Den sender fremdriftsoplysningerne til stderr, ikke stdout.
Du kunne betragte dette som et lille misbrug af stderr, men det er en smart måde at holde normal output og fremdriftsinformation adskilt. Hvis du vil, kan du fortælle curl at vise en fremdriftsmåler som standard, og du kan altid omdirigere output eller fejl, som du vil, uafhængigt af hinanden.

Skriv et svar