Linuxverktygs rörbeteende: Är det en bugg eller en funktion?

Linuxverktygs rörbeteende: Är det en bugg eller en funktion?
Index
  1. Varför har vissa program olika utdata när de pipas?
  2. Och hur gör de detta?
  3. Några exempel på pipe-medvetna kommandon

Upptäck kraften i Linux-pipor! Lär dig hur olika program hanterar utdata och varför formatet förändras beroende på om det pipas, för att optimera ditt arbetsflöde.

Om du har någon erfarenhet av Linux-kommandoraden har du förmodligen använt en pipe för att lösa uppgifter genom att kombinera enkla program. Det är UNIX-sättet.

En pipe kopplar samman en programs utdataflöde med en annan programs indata, men det kan pågå mer bakom kulisserna än vad ögat ser.

Varför har vissa program olika utdata när de pipas?

Titta på ls, ett av de vanligaste och mest användbara kommandona som finns. Du känner kanske till hur det fungerar:

Att köra ls utan argument och utan särskild konfiguration ger dig en lista över filer i den nuvarande katalogen, i fler kolumner. Men titta på vad som händer när du pipar ls:

Här använder jag cat för att demonstrera effekten av att pinga lsutdata. Du kan också skicka ls-utdata till en fil, genom att använda omdirigering, med ett kommando som ls > outputfile.

[enlazatom_show_links]

Det är inte bara ls som gör detta, så varför är en sådan funktion vanlig bland Linux-program? Det visar sig att speciell hantering för pipad utdata kan vara användbar av flera skäl.

I fallet med ls och andra verktyg som producerar formaterad utdata, är det logiskt att förenkla den utdata när den pipas. Kommandot du pipar till förväntar sig indata i ett format med en rad per post, enligt den vanliga Unix-konventionen för radorienterade verktyg. Om ls skickade sin kolumnbaserade utdata till andra program, skulle de tycka att det vore besvärligt, om inte omöjligt, att tolka det korrekt.

Vissa program, särskilt nyare, formaterar sin normala utdata ännu mer, med ANSI-sekvenser för att färga eller kursivera text, till exempel. Återigen skulle sådan text vara komplicerad att tolka för andra verktyg, och allt extra arbete som behövs för att hantera indata är oönskat.

Och hur gör de detta?

När du kör ett program, vidarebefordrar din skalkommando filbeskrivare för standard indata, utdata och felströmmar. Vanligtvis är dessa kopplade till din terminal, så att de tangenter du trycker på kommer via standard indata, och programmets utdata visas på din skärm. Men du kan skicka dessa strömmar någon annanstans, via pipor eller filomdirigering.

För det mesta kommer ett program inte att bry sig om dessa detaljer. Om indata kommer från ditt tangentbord eller en annan process, kommer ett verktyg som grep att behandla dem identiskt. Detta ger oss mycket kraftfulla verktyg som vi kan kombinera på olika sätt. Men som med exemplet av ls ovan, kan ett program ibland behöva veta om en indata- eller utdataström är kopplad till terminalen eller något annat. För det finns C-biblioteksfunktionen isatty:

#include <unistd.h> int isatty(int fd); 

Denna funktion tar ett heltal som representerar en filbeskrivare och returnerar 1 om den refererar till en terminal, 0 annars. Filbeskrivaren kan vara vilket heltal som helst, men värdena 0, 1 och 2 är reserverade för stdin, stdout och stderr, respektive.

Det finns en högre nivå motsvarighet som du kan använda i skalskript: -t test. Detta är en mycket nära motsvarighet till isatty-funktionen:

#!/bin/bash if test -t 0; then echo "standard input is a terminal" else echo "standard input is NOT a terminal" fi 

Programmet beter sig precis som du skulle hoppas och förvänta dig:

Några exempel på pipe-medvetna kommandon

Som nämnts ovan fungerar ls annorlunda när det pipas och beter sig i princip som om -1 alternativet hade skickats. Om du av någon anledning vill åsidosätta detta beteende, använd bara -C alternativet:

ps-kommandot ger information om körande processer, inklusive kommandot som startade varje process. Men eftersom kommandon kan vara väldigt långa, trunkerar programmet hela kommandot för att passa i din terminal:

När du pipar ps-output till en fil, finns det dock inget behov av denna trunkering, så programmet levererar hela kommandon:

grep är ett kraftfullt verktyg som låter dig söka filer efter reguljära uttrycksmönster. Dess färgalternativ markerar matchningar på rätt sätt:

Men när den utdata omdirigeras, gör grep det förnuftiga och slutar producera de specialteckenserier som styr dessa färger. Annars—och du kan testa detta med grep --color=always—kan du få en fil som ser ut så här:

Slutligen är curl en av de mest intressanta användningarna av utdataflödesdetektering. När du skickar det en URL, kommer programmet att skriva ut.

Men om du omdirigerar den utdata till en fil gör curl något bättre än att bara vara tyst:

Även om du inte kan se det i den skärmdumpen, visar curl en dynamisk progressiv mätare som uppdateras när din begäran laddas ner. Det är inte så användbart för en liten webbsida, men för större svar, inklusive stora filnedladdningar, kan denna utdata vara ganska nyttig. Hur gör curl detta, samtidigt som den fortfarande omdirigerar din utdata till filen? Den skickar progressinformationen till stderr, inte stdout.

Du kanske anser detta som en liten missbruk av stderr, men det är ett smart sätt att hålla normal utdata och progressinformation åtskilda. Om du vill kan du be curl att visa en progressiv mätare som standard, och du kan alltid omdirigera utdata eller fel som du vill, oberoende av varandra.

Nu när du har läst klart Linuxverktygs rörbeteende: Är det en bugg eller en funktion?, inbjuder vi dig att utforska kategorin Linux ytterligare. Där hittar du fler intressanta artiklar som kommer att utöka dina kunskaper och hålla dig informerad. Sluta inte läsa och upptäcka mer!

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *

Go up