Index 🏠 || 🔝 Nahoru


Publikováno:

Aktualizováno

Série »Linux shell«

Kategorie:

PSKáčko

Tagy:

Vstup a výstup

Jedním ze základních stavebních kamenů operačního systému Unix je následující přístup:

  • Každý program se chová jako filter.
  • Vždy se předpokládá, že výstup jednoho programu se může stát vstupem druhého programu.
  • Univerzálním komunikačním rozhraním je text.

inout

V Unixu má každý proces (program) standardní vstup stdin, standardní výstup stdout a standardní chybový výstup stderr. Vstup standardně čte z klávesnice vždy, když uživatel stiskne klávesu Enter. Výstup a chybový výstup se během běhu programu vypisuje na terminál, tedy na obrazovku.

1
2
3
4
5
6
7
8
$ wc
Mily studente,

dnes se ucime o OS Unix
Hezky den
^D

4      10      50

Například program wc čte text zadaný z klávesnice a po jeho ukončení (klávesová zkratka Ctrl+D vkládá znak konce souboru) vypíše počet znaků, slov a řádků.

wc

Všechny programy ale nutně nemusí stdin používat. Například program ls, který vypisuje obsah adresáře žádný standardní vstup nečte.

Přesměrování výstupu do souboru

Výstup každého programu je možné přesměrovat do souboru pomocí metaznaku >:

přesměrování popis
>SOUBOR standardní výstup je přesměrován do souboru
>>SOUBOR standardní výstup je připojen na konec souboru
2>SOUBOR standardní chybový výstup je přesměrován do souboru
2>>SOUBOR standardní chybový výstup je připojen na konec souboru
&>SOUBOR oba standardní výstupy jsou přesměrovány do souboru

Například:

1
2
3
4
$ ls . blah
ls: nelze přistoupit k blah: Adresář nebo soubor neexistuje
.:
index.pl  inout.ditaa  inout.png

Program vypíše obsah aktuálního adresáře a adresáře blah. Protože ale adresář blah neexistuje, program vypíše na chybový výstup chybové hlášení.

blah

Nyní výstup přesměrujeme do souboru obsah.txt. Chybové hlášení je stále vidět na terminálu (obrazovce), ale výpis adresáře se provedl do souboru:

1
2
$ ls . blah >obsah.txt
ls: nelze přistoupit k blah: Adresář nebo soubor neexistuje

obsah

Jestliže přesměrujeme do souboru pouze chybový výstup, situace se otočí:

1
2
3
$ ls . blah 2>chyba.txt
.:
index.pl  inout.ditaa  inout.png

chyba

Obsah souboru můžeme vypsat pomocí příkazu cat:

1
2
3
4
5
6
7
$ cat obsah.txt chyba.txt
.:
index.pl
inout.ditaa
inout.png
obsah.txt
/bin/ls: nelze přistoupit k blah: Adresář nebo soubor neexistuje

Při přesměrování lze místo jména SOUBORu použít souborový deskriptor. Ten se zadává ve formátu &CISLO, kde CISLO označuje deskriptor.

deskriptor význam
0 standardní vstup
1 standardní výstup
2 standardní chybový výstup

Příkaz:

1
$ ls . blah >>vystup.txt 2>&1

Přesměruje standardní výstup na konec souboru a zároveň přesměruje chybový výstup na standardní výstup, takže se v souboru vystup.txt objeví stdout(1) i stderr(2).

oba

Zahození výstupu

Speciální soubor /dev/null funguje jako “černá díra” — vše, co se do něj zapíše, se zahodí. Hodí se pro potlačení nežádoucího výstupu:

1
2
3
$ ls . blah 2>/dev/null
.:
index.pl  inout.ditaa  inout.png

Chybové hlášení se zahodí a na obrazovce zůstane jen standardní výstup. Zahození obou výstupů:

1
$ ls . blah &>/dev/null

Přesměrování vstupu ze souboru

Vstup programu lze přesměrovat pomocí metaznaku <. Proces (program) potom nebude číst vstupní data z klávesnice, ale ze souboru.

Jako příklad si uvedeme krátký program v jazyce Python, který provede součet všech čísel zadaných na vstup.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python3
"""Program provede součet všech čísel, které přečte z stdin."""
import sys

soucet = 0
while True:
    try:
        line = input()
        cisla = line.split()
        for c in cisla:
            c = float(c)
            soucet += c
    except EOFError:
        print(soucet)
        exit(0)
    except KeyboardInterrupt:
        sys.stderr.write("Program prerusen uzivatelem\n")
        exit(1)
    except:
        sys.stderr.write("ERROR: '{}' neni cislo\n".format(c))
        exit(2)
1
2
3
4
5
6
$ ./soucet.py
1 2 3
4 5
^D

15.0

Čísla, která se mají sečíst, můžeme zapsat do souboru sectito.txt:

1
2
3
4
5
6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99 100

Potom stačí jednoduše zavolat:

1
2
$ ./soucet.py <sectito.txt
5050.0

Roury

Často je velice užitečné spojit dva programy a výstup jednoho přesměrovat na vstup druhého. Slouží k tomu mechanizmus, který se označuje jako roura (pipe). Pro zřetězení několika programů pomocí roury se používá metaznak |.

1
2
$ ls *.txt | wc -l
15

Výstup programu ls je přesměrován na vstup programu wc, který počítá řádky. Výsledkem je tedy počet souborů s příponou .txt.

roura

Takto lze spojovat do kolony i více programů. Například:

1
2
3
4
5
6
7
8
$ ls -l *.png | cut -d ' ' -f 5,10 | sort -n
3674 roura.png
3842 wc.png
5091 oba.png
5123 blah.png
5909 obsah.png
5947 chyba.png
6417 inout.png

Program ls podrobně vypíše soubory s příponou .png, program cut vybere z výpisu jen dva sloupce a program sort je seřadí podle velikosti.

Příkaz tee

Příkaz tee čte standardní vstup a zapisuje ho současně na standardní výstup i do souboru. Hodí se, když chceme výstup vidět na obrazovce a zároveň ho uložit:

1
2
$ ls -l *.png | tee seznam.txt | wc -l
7

Výstup programu ls se uloží do souboru seznam.txt a zároveň se předá programu wc. S přepínačem -a připojuje na konec souboru (append).

Příkaz xargs

Příkaz xargs čte položky ze standardního vstupu a předává je jako argumenty zadanému příkazu. Hodí se tam, kde příkaz neumí číst ze stdin, ale přijímá data jako argumenty na příkazové řádce.

1
$ ls *.txt | xargs wc -l

je ekvivalentem příkazu

1
$ wc -l soubor1.txt soubor2.txt soubor3.txt

Důležité přepínače:

přepínač popis
-n N předá nanejvýš N argumentů najednou
-I {} nahradí {} aktuální položkou (vhodné pro složitější příkazy)
-P N spustí až N procesů paralelně
-0 očekává položky oddělené znakem NUL místo bílých znaků (kombinuje se s find -print0)
-t před spuštěním každého příkazu ho vypíše na stderr (ladění)
-r nespustí příkaz, pokud je vstup prázdný

Příklady:

1
$ find . -name "*.log" -print0 | xargs -0 rm

Smaže všechny soubory .log — přepínač -print0 a -0 zajistí správné zpracování souborů, jejichž název obsahuje mezery nebo jiné speciální znaky.

1
$ cat seznam.txt | xargs -n 1 curl -O

Stáhne každý URL ze souboru seznam.txt zvlášť — -n 1 zajistí, že se pro každý URL spustí samostatný příkaz curl.

1
$ find . -name "*.py" | xargs -I {} cp {} /zaloha/

Zkopíruje každý .py soubor do adresáře /zaloha/. Zástupný symbol {} se nahradí názvem aktuálně zpracovávaného souboru.

1
$ cat hosts.txt | xargs -P 4 -I {} ping -c 1 {}

Otestuje dostupnost hostitelů ze souboru hosts.txt, přičemž spustí až 4 příkazy ping paralelně.

Pojmenované roury

Rouru není možné použít vždy — například pokud spolu chtějí komunikovat dva procesy, které spouští vždy jiný uživatel. V těchto případech je možné použít pojmenovanou rouru. Tu je třeba nejprve vytvořit a poté je možné s ní pracovat jako by to byl soubor.

1
2
3
$ mkfifo /tmp/mojetrubka
$ chmod a+r /tmp/mojetrubka
$ ls -l *.png | cut -d ' ' -f 5,10  >/tmp/mojetrubka

Jiný uživatel potom může z roury číst

1
$ sort -n </tmp/mojetrubka

Here-string <<<

Here-string je zkratka za rouru z echo/print. Místo

1
2
$ echo  "ahoj světe" | wc -w
$ print "ahoj světe" | wc -w

lze psát

1
$ wc -w <<< "ahoj světe"

Řetězec za <<< se předá jako standardní vstup příkazu — bez vytváření subshell-u a bez dočasného souboru. Hodí se pro jednorázové předání dat příkazu, který čte ze stdin:

1
2
3
4
5
6
7
8
# počet slov v řetězci
wc -w <<< "rychlá hnědá liška"

# převod na velká písmena
tr '[:lower:]' '[:upper:]' <<< "ahoj světe"

# ověření formátu e-mailu regulárním výrazem
grep -E '^[^@]+@[^@]+\.[^@]+$' <<< "user@example.com"

Související posty