Vraag Wat betekent "2> en 1" in de schaal?


In een Unix-shell, als ik wil combineren stderr en stdout in de stdout stream voor verdere manipulatie, kan ik het volgende toevoegen aan het einde van mijn opdracht:

2>&1

Dus, als ik wil gebruiken head op de uitvoer van g++, Ik kan zoiets als dit doen:

g++ lots_of_errors 2>&1 | head

dus ik kan alleen de eerste paar fouten zien.

Ik heb altijd problemen om dit te onthouden, en ik moet het constant opzoeken, en dat komt vooral omdat ik de syntaxis van deze specifieke truc niet volledig begrijp.

Kan iemand dit opbreken en karakter voor karakter uitleggen wat 2>&1  middelen?


1734
2018-05-03 22:57


oorsprong


antwoorden:


Bestandsdescriptor 1 is de standaarduitvoer (stdout).
Bestandsdescriptor 2 is de standaardfout (stderr).

Hier is een manier om dit construct te onthouden (hoewel het niet geheel juist is): in het begin 2>1 lijkt misschien een goede manier om door te sturen stderr naar stdout. Het zal echter feitelijk geïnterpreteerd worden als "redirect stderr naar een bestand met de naam 1". & geeft aan dat wat volgt een bestandsdescriptor is en geen bestandsnaam. Dus het construct wordt: 2>&1.


1942
2018-05-03 23:04



echo test > afile.txt

stuurt stdout om naar afile.txt. Dit is hetzelfde als doen

echo test 1> afile.txt

Om stderr om te leiden, doet u:

echo test 2> afile.txt

>& is de syntaxis om een ​​stream naar een andere descriptor van het bestand om te leiden - 0 is stdin, 1 is stdout en 2 is stderr.

Je kunt stdout omleiden naar stderr door te doen:

echo test 1>&2 # or echo test >&2

Of vice versa:

echo test 2>&1

Dus, kortom ... 2> stuurt stderr door naar een (niet-gespecificeerd) bestand, toevoegend &1 stuurt stderr door naar stdout.


481
2018-05-03 22:59



Enkele trucjes over omleiding

Sommige syntaxis particulariteit hierover kan belangrijke gedragingen hebben. Er zijn enkele kleine voorbeelden van omleidingen, STDERR, STDOUTen argumenten bestellen.

1 - Overschrijven of toevoegen?

Symbool > gemiddelde redirection.

  • > gemiddelde stuur naar een volledig ingevuld bestand, overschrijven doel als het bestaat (zie noclobber bash-functie op # 3 later).
  • >> gemiddelde verzenden als aanvulling op zou toevoegen aan target als deze bestaat.

In elk geval zou het bestand worden aangemaakt als het niet bestaat.

2 - De shell opdrachtregel is afhankelijk van de bestelling !!

Om dit te testen, hebben we dat nodig een eenvoudige opdracht die op beide uitgangen iets zal verzenden:

$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(Verwacht dat je geen map hebt met de naam /tnt, natuurlijk ;). Nou, we hebben het !!

Dus laten we eens kijken:

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1

$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory

De laatste opdrachtregel dumpt STDERR naar de console, en het lijkt niet het verwachte gedrag te zijn ... Maar ...

Als je wat wilt maken na filteren over één uitvoer, de andere of beide:

$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'

$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->

Merk op dat de laatste commandoregel in deze alinea precies hetzelfde is als in de vorige alinea, waar ik schreef lijken niet het verwachte gedrag te zijn (dus dit kan zelfs een verwacht gedrag zijn).

Wel, er zijn een paar trucs over omleidingen, voor verschillende bewerkingen op beide uitgangen:

$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory

Nota: &9descriptor zou spontaan optreden vanwege ) 9>&2.

Addendum: nota! Met de nieuwe versie van  (>4.0) er is een nieuwe functie en meer sexy syntaxis om dit soort dingen te doen:

$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory

En tot slot voor een dergelijke trapsgewijze uitvoeropmaak:

$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
     1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Addendum: nota! Dezelfde nieuwe syntaxis, op beide manieren:

$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
     1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Waar STDOUT ga door een specifiek filter, STDERR naar een andere en tenslotte gaan beide uitgangen samengevoegd door een derde opdrachtfilter.

3 - Een woord over noclobber optie en >| syntaxis

Dat gaat over overschrijven:

Terwijl set -o noclobber instrueer bash aan niet overschrijf een bestaand bestand, de >| syntaxis laat je deze beperking passeren:

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:15 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:19 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:21 CET 2013

Het bestand wordt elke keer overschreven, en nu:

$ set -o noclobber

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

Doorgaan met >|:

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

Deze optie uitschakelen en / of vragen stellen als deze al is ingesteld.

$ set -o | grep noclobber
noclobber           on

$ set +o noclobber

$ set -o | grep noclobber
noclobber           off

$ date > $testfile ; cat $testfile
Mon Jan  7 13:24:27 CET 2013

$ rm $testfile

4 - Laatste trick en meer ...

Voor doorverwijzen beide uitvoer van een opgegeven opdracht, zien we dat een juiste syntaxis zou kunnen zijn:

$ ls -ld /tmp /tnt >/dev/null 2>&1

voor deze speciaal geval, er is een snelkoppelingsyntaxis: &> ... of >&

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

Notitie: als 2>&1 bestaan, 1>&2 is ook een correcte syntaxis:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b- Ik zal je nu laten denken aan:

$ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

$ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

4c- Als u geïnteresseerd bent in meer informatie

Je zou de fijne handleiding kunnen lezen door op:

man -Len -Pless\ +/^REDIRECTION bash

in een  console ;-)


256
2018-04-29 16:33



De nummers verwijzen naar de bestandsdescriptors (fd).

  • Nul is stdin 
  • Een is stdout 
  • Twee is stderr

2>&1 leidt fd 2 naar 1 door.

Dit werkt voor een willekeurig aantal bestandsdescriptors als het programma ze gebruikt.

Je kunt kijken /usr/include/unistd.h als je ze vergeet:

/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */

Dat gezegd hebbende, heb ik C-tools geschreven die niet-standaard bestandsdescriptors gebruiken voor aangepaste logboekregistratie zodat je het niet ziet tenzij je het doorstuurt naar een bestand of zoiets.


67
2018-05-03 22:58



Dat construct verzendt de standaardfoutenstroom (stderr) naar de actueel locatie van standaarduitvoer (stdout) - dit valutaprobleem lijkt te zijn verwaarloosd door de andere antwoorden.

U kunt elke uitvoerhandle naar een andere omleiden met behulp van deze methode, maar deze wordt meestal gebruikt om te kanaliseren stdout en stderr streamt naar een enkele stream voor verwerking.

Enkele voorbeelden zijn:

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

Merk op dat die laatste zal niet direct stderr naar outfile2 - het leidt het om naar wat stdout was toen het argument werd aangetroffen (outfile1) en dan redirects stdout naar outfile2.

Dit staat een aantal behoorlijk geavanceerde trucs toe.


49
2018-05-03 23:54



Ik vond dit briljante bericht over omleiding: Alles over omleidingen

Omleid zowel standaarduitvoer als standaardfout naar een bestand

$ command &> bestand

Deze one-liner maakt gebruik van de &> operator om beide uitvoerstromen om te leiden - stdout en stderr - van opdracht naar bestand. Dit is de snelkoppeling van Bash voor het snel omleiden van beide streams naar dezelfde bestemming.

Hier ziet u hoe de bestandsdescriptor-tabel eruit ziet nadat Bash beide streams heeft omgeleid:

Enter image description here

Zoals je kunt zien, wijzen zowel stdout als stderr nu naar file. Dus alles geschreven naar stdout en stderr wordt geschreven file.

Er zijn verschillende manieren om beide streams om te leiden naar dezelfde bestemming. Je kunt elke stream een ​​voor een omleiden:

$ opdracht> bestand 2> & 1

Dit is een veel gebruikelijkere manier om beide streams om te leiden naar een bestand. Eerst wordt stdout omgeleid naar het bestand en dan wordt stderr gedupliceerd om hetzelfde te zijn als stdout. Dus beide streams wijzen naar file.

Wanneer Bash verschillende omleidingen ziet, worden deze van links naar rechts verwerkt. Laten we door de stappen gaan en zien hoe dat gebeurt. Voordat de commando's worden uitgevoerd, ziet de bestandsbeschrijverstabel van Bash er als volgt uit:

Enter image description here

Nu verwerkt Bash het eerste omleidingsbestand>. We hebben dit eerder gezien en het maakt stdout point to file:

Enter image description here

Volgende Bash ziet de tweede omleiding 2> & 1. We hebben deze doorverwijzing nog niet eerder gezien. Deze dupliceert file descriptor 2 als een kopie van bestandsdescriptor 1 en we krijgen:

Enter image description here

Beide streams zijn doorgestuurd naar het bestand.

Wees hier echter voorzichtig! schrift

opdracht> bestand 2> & 1

is niet hetzelfde als schrijven:

$ command 2> & 1> bestand

De volgorde van doorverwijzingen doet er toe in Bash! Met deze opdracht wordt alleen de standaarduitvoer naar het bestand omgeleid. De stderr zal nog steeds naar de terminal afdrukken. Om te begrijpen waarom dat gebeurt, gaan we opnieuw door de stappen. Dus voordat de opdracht wordt uitgevoerd, ziet de bestandsdescriptor-tabel er als volgt uit:

Enter image description here

Nu verwerkt Bash omleidingen van links naar rechts. Het ziet eerst 2> & 1 dus het dupliceert stderr naar stdout. De bestandsbeschrijvingstabel wordt:

Enter image description here

Nu ziet Bash de tweede omleiding, >file, en het stuurt stdout om naar bestand:

Enter image description here

Zie je wat hier gebeurt? Stdout wijst nu naar het bestand, maar de stderr wijst nog steeds naar de terminal! Alles dat naar stderr wordt geschreven, wordt nog steeds op het scherm afgedrukt! Wees dus heel, heel voorzichtig met de volgorde van doorverwijzingen!

Merk ook op dat in Bash, schrijven

$ command &> bestand

is precies hetzelfde als:

$ opdracht> & bestand


47
2017-10-29 13:04



2>&1 is een POSIX-shellconstruct. Hier is een analyse, token per token:


2: "Standaardfout"output file descriptor.

>&: Dupliceer een uitvoerbestanddescriptor operator (een variant van Outputomleiding operator >). Gegeven [x]>&[y], de bestandsdescriptor aangegeven met x is gemaakt om een ​​kopie te zijn van de descriptor van het uitvoerbestand y.

1 "Standaard uitvoer"output file descriptor.

De uitdrukking 2>&1 kopieert bestandsbeschrijving 1 naar locatie 2, dus alle uitvoer geschreven naar 2 ("standaardfout") in de uitvoeringsomgeving gaat naar hetzelfde bestand als oorspronkelijk beschreven door 1 ("standaarduitvoer").


Verdere uitleg:

Bestandsdescriptor: "Een per-proces uniek, niet-negatief geheel getal dat wordt gebruikt om een ​​open bestand te identificeren met het oog op bestandstoegang."

Standaarduitvoer / fout: Raadpleeg de volgende opmerking in de Redirection sectie van de shell documentatie:

Open bestanden worden weergegeven door decimale getallen die beginnen met nul. De grootst mogelijke waarde is door de implementatie gedefinieerd; alle implementaties ondersteunen echter ten minste 0 tot en met 9 voor gebruik door de toepassing. Deze nummers worden "bestandsdescriptors" genoemd. De waarden 0, 1 en 2 hebben een speciale betekenis en conventioneel gebruik en worden geïmpliceerd door bepaalde omleidingsbewerkingen; ze worden respectievelijk standaardinvoer, standaarduitvoer en standaardfout genoemd. Programma's nemen meestal hun invoer van standaardinvoer en schrijven uitvoer op standaarduitvoer. Foutmeldingen worden meestal op standaardfouten geschreven. De omleidingsoperators kunnen worden voorafgegaan door een of meer cijfers (zonder tussenliggende tekens toegestaan) om het bestandsdescriptornummer aan te duiden.


13
2017-12-25 06:43



Om uw vraag te beantwoorden: het vergt een foutoutput (normaal verzonden naar stderr) en schrijft het naar standaarduitvoer (stdout).

Dit is handig met bijvoorbeeld 'meer' als u voor alle uitvoer moet pagen. Sommige programma's, zoals het afdrukken van gebruiksinformatie in stderr.

Om je te helpen herinneren

  • 1 = standaarduitvoer (waarbij programma's normale uitvoer afdrukken)
  • 2 = standaardfout (waarbij programma's afdrukfouten maken)

"2> & 1" verwijst eenvoudig naar alles dat naar stderr wordt gestuurd, om in plaats daarvan te stdouten.

Ik raad ook aan om te lezen dit bericht op fout doorverwijzing waar dit onderwerp volledig wordt behandeld.


12
2018-05-03 23:24



2 is de standaardfout van de console.

1 is de standaarduitvoer van de console.

Dit is de standaard Unix en Windows volgt ook de POSIX.

Bijv. wanneer je rent

perl test.pl 2>&1

de standaardfout wordt omgeleid naar standaarduitvoer, zodat u beide uitgangen samen kunt zien:

perl test.pl > debug.log 2>&1

Na uitvoering kunt u alle uitvoer, inclusief fouten, zien in debug.log.

perl test.pl 1>out.log 2>err.log

De standaarduitvoer gaat dan naar out.log en standaardfout naar err.log.

Ik stel voor dat je probeert deze te begrijpen.


12
2017-07-19 03:23



Vanuit het oogpunt van een programmeur betekent dit precies dit:

dup2(1, 2);

Zie de man pagina.

Dat te begrijpen 2>&1 is een kopiëren verklaart ook waarom ...

command >file 2>&1

... is niet hetzelfde als ...

command 2>&1 >file

De eerste stuurt beide streams naar file, terwijl de tweede fouten zal verzenden naar stdouten gewone uitvoer in file.


10
2017-12-03 10:20