GNU/Linux >> Znalost Linux >  >> Linux

echo nebo print /dev/stdin /dev/stdout /dev/stderr

stdin , stdout a stderr jsou streamy připojené k deskriptorům souborů 0, 1 a 2 procesu.

Na výzvu interaktivního shellu v terminálu nebo emulátoru terminálu by všechny tyto 3 deskriptory souborů odkazovaly na stejný popis otevřeného souboru, který by byl získán otevřením souboru terminálu nebo pseudoterminálního zařízení (něco jako /dev/pts/0 ) v režimu čtení+zápis.

Pokud z tohoto interaktivního prostředí spustíte skript bez použití jakéhokoli přesměrování, váš skript zdědí tyto deskriptory souborů.

V systému Linux /dev/stdin , /dev/stdout , /dev/stderr jsou symbolické odkazy na /proc/self/fd/0 , /proc/self/fd/1 , /proc/self/fd/2 respektive samy speciální symbolické odkazy na skutečný soubor, který je otevřen na těchto deskriptorech souborů.

Nejsou to stdin, stdout, stderr, jsou to speciální soubory, které identifikují, do kterých souborů stdin, stdout, stderr jdou (všimněte si, že je to jiné v jiných systémech než Linux, které tyto speciální soubory mají).

čtení něčeho ze stdin znamená čtení z deskriptoru souboru 0 (který bude ukazovat někam do souboru, na který odkazuje /dev/stdin ).

Ale v $(</dev/stdin) , shell nečte ze stdin, otevře nový deskriptor souboru pro čtení na stejném souboru jako ten otevřený na stdin (takže čte od začátku souboru, ne tam, kam aktuálně ukazuje stdin).

S výjimkou speciálního případu koncových zařízení otevřených v režimu čtení+zápis nejsou stdout a stderr obvykle otevřeny pro čtení. Jsou určeny jako streamy, do kterých píšete . Takže čtení z deskriptoru souboru 1 obecně nebude fungovat. V systému Linux otevřete /dev/stdout nebo /dev/stderr pro čtení (jako v $(</dev/stdout) ) by fungoval a umožnil by vám číst ze souboru, kam jde stdout (a pokud by stdout byla roura, četl by se z druhého konce roury, a pokud by to byl soket, selhal by, protože nemůžete otevřít zásuvka).

V našem případě skriptu spuštěného bez přesměrování na výzvu interaktivního shellu v terminálu budou všechny /dev/stdin, /dev/stdout a /dev/stderr tímto souborem /dev/pts/x terminálového zařízení.

Čtení z těchto speciálních souborů vrací to, co posílá terminál (to, co píšete na klávesnici). Zapsáním do nich se text odešle do terminálu (pro zobrazení).

echo $(</dev/stdin)
echo $(</dev/stderr)

bude stejný. Chcete-li rozbalit $(</dev/stdin) , shell otevře /dev/pts/0 a čte, co píšete, dokud nestisknete ^D na prázdném řádku. Poté předá rozšíření (to, co jste zadali, zbavené koncových řádků a podléhající split+glob) na echo který jej poté vypíše na stdout (pro zobrazení).

Nicméně v:

echo $(</dev/stdout)

v bash (a bash pouze), je důležité si uvědomit, že uvnitř $(...) , stdout byl přesměrován. Nyní je to potrubí. V případě bash , podřízený proces shellu čte obsah souboru (zde /dev/stdout ) a zapsat jej do roury, zatímco rodič čte z druhého konce, aby vytvořil expanzi.

V tomto případě, když se tento podřízený proces bash otevře /dev/stdout , je to vlastně otevření čtecího konce trubky. Z toho nikdy nic nevzejde, je to patová situace.

Pokud byste chtěli číst ze souboru, na který ukazují skripty stdout, obešli byste to pomocí:

 { echo content of file on stdout: "$(</dev/fd/3)"; } 3<&1

To by duplikovalo fd 1 na fd 3, takže /dev/fd/3 by ukazovalo na stejný soubor jako /dev/stdout.

Se skriptem jako:

#! /bin/bash -
printf 'content of file on stdin: %s\n' "$(</dev/stdin)"
{ printf 'content of file on stdout: %s\n' "$(</dev/fd/3)"; } 3<&1
printf 'content of file on stderr: %s\n' "$(</dev/stderr)"

Při spuštění jako:

echo bar > err
echo foo | myscript > out 2>> err

Uvidíte v out poté:

content of file on stdin: foo
content of file on stdout: content of file on stdin: foo
content of file on stderr: bar

Pokud na rozdíl od čtení z /dev/stdin , /dev/stdout , /dev/stderr , chtěli jste číst ze stdin, stdout a stderr (což by dávalo ještě menší smysl), udělali byste:

#! /bin/sh -
printf 'what I read from stdin: %s\n' "$(cat)"
{ printf 'what I read from stdout: %s\n' "$(cat <&3)"; } 3<&1
printf 'what I read from stderr: %s\n' "$(cat <&2)"

Pokud jste tento druhý skript spustili znovu jako:

echo bar > err
echo foo | myscript > out 2>> err

Uvidíte v out :

what I read from stdin: foo
what I read from stdout:
what I read from stderr:

a v err :

bar
cat: -: Bad file descriptor
cat: -: Bad file descriptor

Pro stdout a stderr cat selže, protože deskriptory souborů byly otevřeny pro zápis pouze, nečíst, rozšíření $(cat <&3) a $(cat <&2) je prázdný.

Pokud jste to nazvali:

echo out > out
echo err > err
echo foo | myscript 1<> out 2<> err

(kde <> otevře v režimu čtení+zápis bez zkrácení), uvidíte v out :

what I read from stdin: foo
what I read from stdout:
what I read from stderr: err

a v err :

err

Všimnete si, že ze stdout nebylo nic načteno, protože předchozí printf přepsal obsah out s what I read from stdin: foo\n a hned poté opustil pozici stdout v tomto souboru. Pokud jste vytvořili out s nějakým větším textem, například:

echo 'This is longer than "what I read from stdin": foo' > out

Pak byste se dostali do out :

what I read from stdin: foo
read from stdin": foo
what I read from stdout: read from stdin": foo
what I read from stderr: err

Podívejte se, jak $(cat <&3) přečetl to, co zbylo po prvním printf a tím se také posunula střední pozice za ni takže další printf vypíše to, co bylo přečteno poté.


stdout a stderr jsou výstupy, nečtete z nich, můžete do nich pouze zapisovat. Například:

echo "this is stdout" >/dev/stdout
echo "this is stderr" >/dev/stderr

programy standardně zapisují do stdout, takže první je ekvivalentní s

echo "this is stdout"

a stderr můžete přesměrovat jinými způsoby, například

echo "this is stderr" 1>&2

Linux
  1. Jak Linux zpracovává více po sobě jdoucích oddělovačů cest (/home////username///soubor)?

  2. Kdy použít /dev/random vs /dev/urandom?

  3. Co jsou soubory /dev/zero a /dev/null v Linuxu

  1. Jak kódovat base64 /dev/random nebo /dev/urandom?

  2. Kdy mám použít /dev/shm/ a kdy /tmp/?

  3. DD z /dev/zero do /dev/null...co se vlastně stane

  1. /dev/sdb:Žádný takový soubor nebo adresář (ale /dev/sdb1 atd. existuje)

  2. Linux:Rozdíl mezi /dev/console , /dev/tty a /dev/tty0

  3. jádro:deaktivace /dev/kmem a /dev/mem