Vraag Wat is het verschil tussen "Redirection" en "Pipe"?


Deze vraag klinkt misschien een beetje stom, maar ik zie het verschil tussen omleiding en buizen niet echt.

Omleiding wordt gebruikt om de stdout / stdin / stderr om te leiden, b.v. ls > log.txt.

Pijpen worden gebruikt om de uitvoer van een opdracht als invoer voor een ander commando, b.v. ls | grep file.txt.

Maar waarom zijn er twee exploitanten voor hetzelfde?

Waarom niet gewoon schrijven ls > grep om de output door te geven, is dit niet gewoon een soort van omleiding ook? Wat ik mis?


173
2017-08-07 13:22


oorsprong




antwoorden:


Pijp wordt gebruikt om de uitvoer naar een andere door te geven programma of hulpprogramma.

Omleiding wordt gebruikt om de uitvoer door te geven aan een van beide bestand of stream.

Voorbeeld: thing1 > thing2 vs thing1 | thing2

thing1 > thing2

  1. Uw shell zal het programma met de naam uitvoeren thing1
  2. Alles dat thing1 uitgangen worden geplaatst in een bestand met de naam thing2. (Opmerking - indien thing2 bestaat, het zal overschreven worden)

Als u de uitvoer van het programma wilt doorgeven thing1 naar een programma genaamd thing2, je zou het volgende kunnen doen:

thing1 > temp_file && thing2 < temp_file

welke zou

  1. voer programma genoemd uit thing1
  2. sla de uitvoer op in een bestand met de naam temp_file
  3. voer programma genoemd uit thing2, doe alsof de persoon op het toetsenbord de inhoud van getypt heeft temp_file als de invoer.

Dat is echter onhandig, dus maakten ze pijpen als een eenvoudigere manier om dat te doen. thing1 | thing2 doet hetzelfde thing1 > temp_file && thing2 < temp_file

EDIT om meer details te geven aan de vraag in commentaar:

Als > geprobeerd om zowel "pass to program" als "write to file" te zijn, het zou problemen in beide richtingen kunnen veroorzaken.

Eerste voorbeeld: U probeert naar een bestand te schrijven. Er bestaat al een bestand met die naam dat u wilt overschrijven. Het bestand is echter uitvoerbaar. Vermoedelijk zou het proberen om dit bestand uit te voeren, waarbij de invoer wordt doorgegeven. U zou iets moeten doen, zoals de uitvoer naar een nieuwe bestandsnaam schrijven en vervolgens het bestand hernoemen.

Tweede voorbeeld: Zoals Florian Diesch opmerkte, wat als er een andere opdracht elders in het systeem met dezelfde naam is (dat is in het execute-pad). Als je van plan was een bestand met die naam in je huidige map te maken, zat je vast.

Ten derde: als je een commando verkeerd typt, zou het je niet waarschuwen dat het commando niet bestaat. Op dit moment, als je typt ls | gerp log.txt het zal het je vertellen bash: gerp: command not found. Als > betekende beide, het zou gewoon een nieuw bestand voor je maken (waarschuw dan dat het niet weet wat te doen met log.txt).


194
2017-08-07 13:30



Dank je. Je noemde thing1 > temp_file && thing2 < temp_file om het makkelijker te doen met pijpen. Maar waarom hergebruik niet de > operator om dit te doen, b.v. thing1 > thing2 voor opdrachten thing1 en thing2 ? Waarom een ​​extra operator | ? - John Threepwood
"Neem de uitvoer en schrijf deze naar een bestand" is een andere actie dan "Neem de uitvoer en geef deze door aan een ander programma". Ik zal meer gedachten in mijn antwoord bewerken ... - David Oneill
@JohnThreepwood Ze hebben verschillende betekenissen. Wat als ik iets naar een bestand met de naam wil omleiden less, bijvoorbeeld? thing | less en thing > less zijn volkomen verschillend, omdat ze andere dingen doen. Wat u voorstelt zou een dubbelzinnigheid creëren. - Darkhogg
Is het juist om te zeggen dat "thing1> temp_file" slechts syntactische suiker is voor "thing1 | tee temp_file"? Sinds ik weet wat tee is, gebruik ik bijna nooit omleidingen. - Sridhar-Sarnobat
@ Sridhar-Sarnobat nee, de tee commando doet iets anders. tee schrijft uitvoer naar zowel het scherm (stdout) en het bestand. Omleiding doet het enkel en alleen het bestand. - David Oneill


Als de betekenis van foo > bar zou afhangen van het feit of er een commando met de naam is bar dat zou het gebruik van omleiding een stuk moeilijker en meer foutgevoelig maken: elke keer als ik wil omleiden naar een bestand, moest ik eerst controleren of er een commando was met de naam "mijn doelbestand".


19
2017-08-07 13:40



Dit zou alleen een probleem zijn als u schrijft naar bar in een map die deel uitmaakt van uw $PATH env-variabele. Als je in zoiets als / bin zit, kan ot een probleem zijn. Maar zelfs dan, bar zou een uitvoerbare permissieset moeten hebben, zodat shell niet alleen controleert voor het vinden van een uitvoerbaar bestand bar maar kan het eigenlijk uitvoeren. En als het gaat om het overschrijven van bestaand bestand, noclober shell-optie moet voorkomen dat bestaande bestanden in omleidingen worden overschreven. - Sergiy Kolodyazhnyy


Er is een essentieel verschil tussen de twee operators:

  1. ls > log.txt -> Met deze opdracht wordt de uitvoer naar het bestand log.txt verzonden.

  2. ls | grep file.txt -> Deze opdracht stuurt de uitvoer van de opdracht ls naar grep door het gebruik van pipe (|) en de opdracht grep zoekt naar file.txt in de invoer die het vorige commando eraan heeft gegeven.

Als u dezelfde taak zou moeten uitvoeren met behulp van het eerste scenario, zou het zijn:

ls > log.txt; grep 'file.txt' log.txt

Dus een pijp (met |) wordt gebruikt om de uitvoer naar een andere opdracht te verzenden, terwijl omleiding (met >) wordt gebruikt om de uitvoer naar een bestand om te leiden.


11
2017-08-07 13:32





Uit het Unix en Linux System Administration Handbook:

Redirection

De shell interpreteert de symbolen <,> en >> als instructies om een ​​a om te leiden commando's invoer of uitvoer naar of van een het dossier.

pipes

Om de STDOUT van één te verbinden opdracht naar de STDIN van een ander gebruik de | symbool, algemeen bekend als een pijp.

Dus mijn interpretatie is: als het commando is om te bevelen, gebruik dan een pijp. Gebruik de omleiding als u naar of van een bestand uitvoert.


9
2018-02-16 00:40





Er is een groot syntactisch verschil tussen de twee:

  1. Een omleiding is een argument voor een programma
  2. Een pijp scheidt twee opdrachten

U kunt dit soort omleidingen bedenken: cat [<infile] [>outfile]. Dit impliceert dat de volgorde er niet toe doet: cat <infile >outfile is hetzelfde als cat >outfile <infile. Je kunt zelfs doorverwijzingen mixen met andere argumenten: cat >outfile <infile -b en cat <infile -b >outfile zijn beide prima. Ook kunt u meer dan één invoer of uitvoer samenvoegen (ingangen worden opeenvolgend gelezen en alle uitvoer wordt naar elk uitvoerbestand geschreven): cat >outfile1 >outfile2 <infile1 <infile2. Het doel of de bron van een omleiding kan een bestandsnaam of de naam van een stream zijn (zoals & 1, ten minste in bash).

Maar pijpen scheiden de ene opdracht volledig van de andere opdracht, je kunt ze niet combineren met argumenten:

[command1] | [command2]

De pipe neemt alles op in de standaarduitvoer van opdracht 1 en verzendt deze naar de standaardinvoer van opdracht2.

Je kunt ook piping en omleiding combineren. Bijvoorbeeld:

cat <infile >outfile | cat <infile2 >outfile2

De eerste cat zal lijnen van infile lezen, dan tegelijkertijd elke regel schrijven naar outfile en naar de tweede sturen cat.

In de seconde cat, standaard input leest eerst uit de pipe (de inhoud van infile), leest vervolgens uit infile2 en schrijft elke regel naar outfile2. Nadat dit is uitgevoerd, wordt outfile een kopie van infile en outfile2 bevat infile gevolgd door infile2.

Ten slotte, doe je eigenlijk iets dat echt lijkt op je voorbeeld door "here string" omleiding (alleen bash-familie) en backticks te gebruiken:

grep blah <<<`ls`

zal hetzelfde resultaat geven als

ls | grep blah

Maar ik denk dat de omleidingsversie eerst alle uitvoer van ls in een buffer (in het geheugen) leest en vervolgens die buffer één regel tegelijk toevoegt, terwijl de piped-versie elke regel uit ls neemt zodra die verschijnt. en geef die regel door aan grep.


3
2017-08-23 22:24



Nitpick: bestel kwesties in doorverwijzing als je een fd naar een andere omleidt: echo yes 1>&2 2>/tmp/blah; wc -l /tmp/blah; echo yes 2>/tmp/blah 1>&2; wc -l /tmp/blah Verder zal omleiding naar een bestand alleen de laatste omleiding gebruiken. echo yes >/tmp/blah >/tmp/blah2 zal alleen schrijven naar /tmp/blah2. - muru
Omleiden is eigenlijk geen argument voor het programma. Het programma zal niet weten of geven waar zijn uitvoer naartoe gaat (of de invoer komt van). Het is gewoon een manier om bash te vertellen hoe dingen moeten worden geregeld voordat het programma wordt uitgevoerd. - Alois Mahdal


Om aan de andere antwoorden toe te voegen, zijn er ook subtiele semantische verschillen - bijv. pijpen sluiten gemakkelijker dan omleidingen:

seq 5 | (head -n1; head -n1)                # just 1
seq 5 > tmp5; (head -n1; head -n1) < tmp5   # 1 and 2
seq 5 | (read LINE; echo $LINE; head -n1)   # 1 and 2

In het eerste voorbeeld, wanneer de eerste oproep naar head eindigt, het sluit de pijp, en seq wordt beëindigd, dus er is geen invoer beschikbaar voor de tweede head.

In het tweede voorbeeld verbruikt head de eerste regel, maar wanneer deze wordt gesloten, is deze de eerste regel stdin  pijp, blijft het bestand open voor de volgende oproep die moet worden gebruikt.

Het derde voorbeeld laat zien dat als we gebruiken read om te voorkomen dat de pijp wordt gesloten, is deze nog steeds beschikbaar in het subproces.

Dus de "stream" is het ding dat we data doorgeven (stdin etc), en is hetzelfde in beide gevallen, maar de pipe verbindt streams van twee processen, waarbij een omleiding een stream verbindt tussen een proces en een bestand, zodat je kan de bron van zowel de overeenkomsten als de verschillen zien.

Postscriptum Als je zo nieuwsgierig bent naar en / of verrast door die voorbeelden zoals ik was, kun je verder graven met behulp van trap om te zien hoe de processen oplossen, bijv .:

(trap 'echo seq EXITed >&2' EXIT; seq 5) | (trap 'echo all done' EXIT; (trap 'echo first head exited' EXIT; head -n1)
echo '.'
(trap 'echo second head exited' EXIT; head -n1))

Soms wordt het eerste proces eerder afgesloten 1 wordt afgedrukt, soms daarna.

Ik vond het ook interessant om te gebruiken exec <&- om de stream van de omleiding af te sluiten om het gedrag van de pijp te benaderen (zij het met een fout):

seq 5 > tmp5
(trap 'echo all done' EXIT
(trap 'echo first head exited' EXIT; head -n1)
echo '.'
exec <&-
(trap 'echo second head exited' EXIT; head -n1)) < tmp5`

2
2018-06-05 00:54



"wanneer de eerste call-to-head is voltooid, wordt de pijp gesloten". Dit is om twee redenen eigenlijk onnauwkeurig. Eén, (hoofd -n1; hoofd -n1) is een subschaal met twee commando's, waarvan elk het eindsuiteinde van pijp overleeft als descriptor 0, en dus subschaal EN elk commando heeft die bestandsbeschrijving geopend. Tweede reden, dat zie je met strace -f bash -c 'seq 5 | (hoofd -n1; hoofd -n1) '. Dus first head sluit alleen de kopie van de bestandsdescriptor - Sergiy Kolodyazhnyy
Het derde voorbeeld is ook onnauwkeurig, omdat read verbruikt alleen de eerste regel (dat is één byte voor 1 en newline). seq verzonden in totaal 10 bytes (5 nummers en 5 nieuwe regels). Dus er zijn nog 8 bytes over in de pipe buffer, en dat is waarom de tweede head werkt - er zijn nog gegevens beschikbaar in pipe buffer. Btw, het hoofd verlaat alleen als er 0 bytes zijn gelezen, een beetje zoals in head /dev/null - Sergiy Kolodyazhnyy
Bedankt voor de verduidelijking. Begrijp ik het goed dat in seq 5 | (head -n1; head -n1) de eerste oproep leegt de pijp, dus deze bestaat nog steeds in een open staat maar zonder gegevens voor de tweede oproep head? Dus het verschil in gedrag tussen de pijp en de omleiding is omdat de kop alle gegevens uit de pijp trekt, maar alleen de 2 lijnen uit de bestandsingang? - Julian de Bhal
Dat is correct. En het is iets dat gezien kan worden strace commando gaf ik in de eerste opmerking. Met omleiding bevindt het tmp-bestand zich op de schijf, waardoor het zoekbaar is (omdat ze het gebruiken lseek() syscall - commando's kunnen van het eerste naar het laatste over het bestand springen, hoe ze ook willen. Maar leidingen zijn sequentieel en niet zoekbaar. Dus de enige manier voor het hoofd om zijn werk te doen is om alles eerst te lezen, of als het bestand groot is - breng een deel ervan naar RAM via mmap() noemen. Ik heb ooit mijn eigen gedaan tail in Python, en kwam precies hetzelfde probleem tegen. - Sergiy Kolodyazhnyy
Het is ook belangrijk om te onthouden dat het leesuiteinde van de pipe (bestandsdescriptor) eerst aan de subshell wordt gegeven (...), en de subshell zal een kopie van zijn eigen stdin maken naar elk commando binnenin (...). Dus ze worden technisch gelezen vanuit hetzelfde object. Eerste head  denkt dat het leest van zijn eigen stdin. Tweede head denkt dat het zijn eigen stdin heeft. Maar in werkelijkheid is hun fd # 1 (stdin) gewoon een kopie van dezelfde fd, die aan het einde van de pijp wordt gelezen. Ik heb ook een antwoord geplaatst, dus misschien helpt het om dingen te verduidelijken. - Sergiy Kolodyazhnyy


Opmerking: het antwoord geeft mijn eigen begrip van deze mechanismen weer up to date, verzameld over onderzoek en het lezen van de antwoorden door de peers op deze site en unix.stackexchange.com, en zal worden bijgewerkt naarmate de tijd vordert. Aarzel niet om vragen te stellen of verbeteringen aan te brengen in de opmerkingen. Ik stel ook voor dat je probeert te zien hoe syscalls in de shell werken strace opdracht. Laat je alsjeblieft niet intimideren door het begrip van internals of syscalls - je hoeft ze niet te kennen of te kunnen gebruiken om te begrijpen hoe shell dingen doet, maar ze helpen zeker om te begrijpen.

TL; DR

  • | pijpen zijn niet geassocieerd met een invoer op schijf, daarom geen inode hebben aantal schijfbestandssysteem (maar inode wel pipefs virtueel bestandssysteem in kernel-space), maar omleidingen bevatten vaak bestanden die wel schijfinvoer hebben en daarom een ​​overeenkomstige inode hebben.
  • pijpen zijn dat niet lseek()'dus commando's kunnen sommige gegevens niet lezen en dan terugspoelen, maar wanneer je omleidt met > of < meestal is het een bestand dat is lseek() object, zodat commando's kunnen navigeren zoals ze willen.
  • omleidingen zijn manipulaties van bestandsdescriptors, die veel kunnen zijn; pipes hebben slechts twee bestandsdescriptors: een voor de linker opdracht en een voor de rechter opdracht
  • omleiding op standaard streams en leidingen zijn beide gebufferd.
  • pijpen hebben bijna altijd betrekking op forking, doorverwijzingen - niet altijd
  • pipes hebben altijd te maken met bestandsdescriptors, omleidingen - gebruik ofwel actuele bestanden met bestandsnaam op schijf, of bestandsdescriptors.
  • pipes zijn de Inter-Process Communication-methode, terwijl omleidingen slechts manipulaties zijn van open bestanden of bestandsachtige objecten
  • beide gebruiken dup2() syscalls onder de kap om kopieën van bestandsdescriptors te leveren, waar de feitelijke gegevensstroom plaatsvindt.
  • omleidingen kunnen "globaal" worden toegepast met exec ingebouwd commando (zie deze en deze ), dus als je dat doet exec > output.txt elke opdracht zal schrijven naar output.txt vanaf toen. | leidingen worden alleen toegepast voor de huidige opdracht (dit betekent ofwel een eenvoudige opdracht of een subschaal zoals seq 5 | (head -n1; head -n2)of samengestelde commando's.
  • Wanneer omleiding wordt uitgevoerd op bestanden, dingen zoals echo "TEST" > file en echo "TEST" >> file beide gebruiken open() syscall op dat bestand (zie ook) en krijg er een bestandsdescriptor van om het door te geven dup2(). pipes | alleen gebruiken pipe() en dup2() syscall.

Invoering

Om te begrijpen hoe deze twee mechanismen verschillen, is het noodzakelijk om hun essentiële eigenschappen, de geschiedenis achter de twee en hun oorsprong in de C-programmeertaal te begrijpen. In feite weten wat bestandsbeschrijvingen zijn en hoe dup2() en pipe() systeemoproepen werk is essentieel, evenals lseek(). Shell is bedoeld als een manier om deze mechanismen abstract te maken voor de gebruiker, maar het graven dieper dan de abstractie helpt de ware aard van het gedrag van de shell te begrijpen.

The Origins of Redirections and Pipes

Volgens het artikel van Dennis Ritche Profetische rotstekeningen, pijpen zijn ontstaan ​​uit een 1964 interne memo door Malcolm Douglas McIlroy, op het moment dat ze aan het werken waren Multics besturingssysteem. Citaat:

Om mijn grootste zorgen in een notendop te zetten:

  1. We moeten een aantal manieren hebben om programma's zoals tuinslang aan te sluiten - schroef in een ander segment wanneer het nodig is om gegevens op een andere manier te masseren. Dit is ook de manier van IO.

Wat wel duidelijk is, is dat programma's op dat moment in staat waren om naar schijf te schrijven, maar dat was inefficiënt als de uitvoer groot was. Om de uitleg van Brian Kernighan in te citeren Unix Pipeline video:

Ten eerste hoef je niet één groot, massaal programma te schrijven - je hebt bestaande kleinere programma's die misschien al een deel van het werk doen ... Een andere is dat het mogelijk is dat de hoeveelheid gegevens die je verwerkt niet zou passen als je hebt het in een bestand opgeslagen ... want onthoud, we zijn terug in de dagen dat schijven over deze dingen, als je geluk had, een Megabyte of twee gegevens waren ... Dus de pijplijn hoefde nooit de hele output te instantiëren .

Het conceptuele verschil is dus duidelijk: pijpen zijn een mechanisme om programma's met elkaar te laten praten. Redirecties - zijn manier van schrijven naar bestand op basisniveau. In beide gevallen maakt shell deze twee dingen gemakkelijk, maar onder de motorkap is er veel gaande.

Dieper gaan: syscalls en interne werking van de shell

We beginnen met het idee van bestandsdescriptor. Bestandsdescriptors beschrijven in principe een open bestand (of dat nu een bestand op schijf is, of in het geheugen, of een anoniem bestand), wat wordt weergegeven door een geheel getal. De twee standaard datastreams  (stdin, stdout, stderr) zijn bestandsdescriptoren respectievelijk 0,1 en 2. Waar komen ze vandaan ? Welnu, in shell-opdrachten worden de bestandsdescriptors overgenomen van hun parent-shell. En het is in het algemeen waar voor alle processen - het proces van het kind neemt de descriptors van het ouderbestand over. Voor daemons het is gebruikelijk om alle overgenomen bestandsdescriptors en / of omleidingen naar andere plaatsen te sluiten.

Terug naar doorverwijzing. Wat is het echt? Het is een mechanisme dat de shell opdracht geeft om bestandsdescriptors voor te bereiden voor opdracht (omdat omleidingen worden gedaan door shell voordat de opdracht wordt uitgevoerd) en ze te wijzen waar de gebruiker heeft voorgesteld. De standaard definitie van uitvoeromleiding is

[n]>word

Dat [n] er is het bestandsdescriptornummer. Wanneer je dat doet echo "Something" > /dev/null het getal 1 is daar geïmpliceerd, en echo 2> /dev/null.

Onder de motorkap wordt dit gedaan door bestandsdescriptor te dupliceren via dup2() systeemoproep. Laten we nemen df > /dev/null. De shell maakt een kinderproces waarbij df loopt, maar daarvoor zal het openen /dev/null als bestandsdescriptor # 3, en dup2(3,1) wordt uitgegeven, die een kopie van bestandsdescriptor 3 maakt en de kopie wordt 1. U weet hoe u twee bestanden hebt file1.txt en file2.txten wanneer je dat doet cp file1.txt file2.txt je hebt twee dezelfde bestanden, maar je kunt ze onafhankelijk manipuleren? Dat is ongeveer hetzelfde wat hier gebeurt. Vaak kun je dat zien voordat je begint, de bash zal ik doen dup(1,10) om een ​​kopiebestanddescriptor # 1 te maken die dat is stdout (en die kopie zal fd # 10 zijn) om hem later te herstellen. Belangrijk is om op te merken dat wanneer u overweegt ingebouwde commando's (die deel uitmaken van de shell zelf en geen bestand hebben /bin of elders) of eenvoudige commando's in een niet-interactieve shell, de shell maakt geen kindproces aan.

En dan hebben we dingen als [n]>&[m] en [n]&<[m]. Dit zijn duplicerende bestandsdescriptors, hetzelfde mechanisme als dup2() alleen nu bevindt het zich in de shell-syntaxis, handig beschikbaar voor de gebruiker.

Een van de belangrijke dingen om op te merken over omleiding is dat hun volgorde niet vast is, maar van belang is voor hoe shell interpreteert wat de gebruiker wil. Vergelijk het volgende:

# Make copy of where fd 2 points , then redirect fd 2
$ ls -l /proc/self/fd/  3>&2  2> /dev/null
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
lrwx------ 1 runner user 64 Sep 13 00:08 3 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/29/fd

# redirect fd #2 first, then clone it
$ ls -l /proc/self/fd/    2> /dev/null 3>&2
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
l-wx------ 1 user user 64 Sep 13 00:08 3 -> /dev/null
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/31/fd

Het praktische gebruik hiervan in shell-scripting kan veelzijdig zijn:

en vele anderen.

Loodgieter met pipe() en dup2()

Dus hoe worden pijpen gemaakt? Via pipe() syscall, die als invoer een array (aka lijst) zal opnemen pipefd van twee items van het type int (geheel getal). Die twee gehele getallen zijn bestanddescriptoren. De pipefd[0] wordt het leesuiteinde van de pijp en pipefd[1] zal het einde van het schrijven zijn. Dus in df | grep 'foo', grep krijgt een kopie van pipefd[0] en df krijgt een kopie van pipefd[1]. Maar hoe ? Natuurlijk met de magie van dup2() syscall. Voor df in ons voorbeeld laten we zeggen pipefd[1] heeft # 4, dus de schaal zal een kind maken, doen dup2(4,1) (onthoud waarom cp voorbeeld?), en dan doen execve() om daadwerkelijk te rennen df. Van nature, df zal bestandsdescriptor # 1 erven, maar zal zich niet bewust zijn dat het niet langer naar terminal verwijst, maar naar fd # 4, wat eigenlijk het write-end van de pipe is. Natuurlijk zal hetzelfde gebeuren met grep 'foo' behalve met verschillende aantallen bestandsdescriptors.

Nu, interessante vraag: kunnen we ook pijpen maken die fd # 2 omleiden, niet alleen fd # 1? Ja, dat is het in feite |&doet in bash. De POSIX-standaard vereist shell-commandotaal om te ondersteunen df 2>&1 | grep 'foo' syntaxis voor dat doel, maar bash doet |& ook.

Het is belangrijk op te merken dat pijpen altijd omgaan met bestandsdescriptors. Er bestaat FIFO of named pipe, die een bestandsnaam op schijf heeft en je kunt het als een bestand gebruiken, maar gedraagt ​​je als een pijp. Maar de | soorten buizen zijn wat bekend staat als anonieme pijp - ze hebben geen bestandsnaam, omdat ze eigenlijk maar twee objecten met elkaar zijn verbonden. Het feit dat we niet met bestanden te maken hebben, heeft ook een belangrijke implicatie: pijpen zijn dat niet lseek()'Staat. Bestanden, hetzij in het geheugen of op schijf, zijn statisch - programma's kunnen gebruiken lseek() syscall om naar byte 120 te springen, vervolgens terug naar byte 10 en vervolgens helemaal naar het einde. Pijpen zijn niet statisch - ze zijn opeenvolgend en daarom kun je de gegevens die je van hen ontvangt niet terugspoelen lseek(). Dit is wat sommige programma's bewust maakt als ze uit een bestand of uit een pijp lezen en dus de nodige aanpassingen kunnen maken voor efficiënte prestaties; met andere woorden, a prog kan detecteren of ik het doe cat file.txt | prog of prog < input.txt. Echt werk bijvoorbeeld staart.

De andere twee zeer interessante eigenschap van pijpen is dat ze een buffer hebben, wat op Linux is 4096 bytes, en ze hebben eigenlijk een bestandssysteem zoals gedefinieerd in Linux broncode ! Ze zijn niet alleen een object om gegevens door te geven, ze zijn zelf een datastructuur! In feite bestaat er een pipefs-bestandssysteem, dat zowel pipes als FIFO's beheert, buizen hebben een inode nummer op hun respectieve bestandssysteem:

# Stdout of ls is wired to pipe
$ ls -l /proc/self/fd/  | cat  
lrwx------ 1 user user 64 Sep 13 00:02 0 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:02 1 -> pipe:[15655630]
lrwx------ 1 user user 64 Sep 13 00:02 2 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:02 3 -> /proc/22/fd
# stdin of ls is wired to pipe
$ true | ls -l /proc/self/fd/0
lr-x------ 1 user user 64 Sep 13 03:58 /proc/self/fd/0 -> 'pipe:[54741]'

Op Linux-buizen zijn unidirectioneel, net als doorverwijzing. Op sommige Unix-achtige implementaties - zijn er bidirectionele leidingen. Hoewel met magie van shell-scripting, je kunt maken bidirectionele leidingen op Linux ook.

Zie ook:


2
2017-09-12 09:26