MC, 2012
Ilustracja do artykułu: Linux stdin, stdout, stderr — Strumienie i przekierowania II

Linux stdin, stdout, stderr — Strumienie i przekierowania II

Ciąg dalszy artykułu na temat standardowych strumieni. Poprzednio omówione zostały przekierowania strumieni wejścia i wyjścia (Linux stdin, stdout, stderr — Strumienie i przekierowania I). W tej części omówimy łączenie strumieni oraz przekierowanie strumienia błędów.

Łączenie strumienia wyjścia jednego programu, ze strumieniem wejścia innego

Wydaje mi się, że łączenie strumieni różnych programów to największa zaleta wypływająca z całego zagadnienia. Dzięki temu możemy sprzęgać ze sobą pomniejsze aplikacje, tworząc taką hybrydę, która zdziała dokładnie to, czego potrzebujemy. Doświadczenie uczy mnie, że praktycznie nie ma operacji na plikach, czy na ich treści, której nie można wykonać w prosty sposób przy pomocy połączonych ze sobą narzędzi, dostępnych w systemie. Łączenie strumieni odbywa się za pomocą symbolu |. Strumień wyjściowy polecenia, które wykonywane jest przed znakiem | przekierowany zostanie do strumienia wejściowego polecenia stojącego po stronie prawej. Spójrzmy na przykład:
$ cat --help
Składnia: cat [OPCJA]... [PLIK]...
Połączenie PLIKU(ÓW) albo przekazanie ze standardowego wejścia na wyjście.

  -A, --show-all           równoważne -vET
  -b, --number-nonblank    numerowanie niepustych linii na wyjściu
  -e                       równoważne -vE
  -E, --show-ends          wypisanie $ na końcu każdej linii
  -n, --number             numerowanie wszystkich linii na wyjściu
  -s, --squeeze-blank      nigdy więcej niż jedna pusta linia
  -t                       równoważne -vT
  -T, --show-tabs          wypisanie znaków TAB jako ^I
  -u                       (ignorowane)
  -v, --show-nonprinting   użycie zapisu ^ i M-, oprócz LFD i TAB
      --help     wyświetlenie tego opisu i zakończenie
      --version  wyświetlenie informacji o wersji i zakończenie

Jeżeli nie został podany PLIK albo podany jest jako -, czytane jest
standardowe wejście.

Przykłady:
  cat f - g  Skopiowanie zawartości f na standardowe wyjście, potem
              zawartości g.
  cat        Skopiowanie standardowego wejścia na standardowe wyjście.

Raporty o błędach cat wysyłaj do bug-coreutils@gnu.org
strona domowa GNU coreutils: http://www.gnu.org/software/coreutils/
Pomoc w używaniu oprogramowania GNU: http://www.gnu.org/gethelp/
O błędach tłumaczenia cat poinformuj przez http://translationproject.org/team/
Żeby przeczytać kompletną dokumentację, uruchom: info coreutils 'cat invocation'
$ cat --help | head
Składnia: cat [OPCJA]... [PLIK]...
Połączenie PLIKU(ÓW) albo przekazanie ze standardowego wejścia na wyjście.

  -A, --show-all           równoważne -vET
  -b, --number-nonblank    numerowanie niepustych linii na wyjściu
  -e                       równoważne -vE
  -E, --show-ends          wypisanie $ na końcu każdej linii
  -n, --number             numerowanie wszystkich linii na wyjściu
  -s, --squeeze-blank      nigdy więcej niż jedna pusta linia
  -t                       równoważne -vT
$ cat --help | head | tail -n 3
  -n, --number             numerowanie wszystkich linii na wyjściu
  -s, --squeeze-blank      nigdy więcej niż jedna pusta linia
  -t                       równoważne -vT
$ cat --help | head | tail -n 3 | grep "numerowanie"
  -n, --number             numerowanie wszystkich linii na wyjściu
Jak widzimy, przekierowując strumienie do kolejnych programów, ograniczaliśmy wyświetlaną treść. No koniec, oczywiście moglibyśmy to przekierować do pliku, lub dalej modyfikować strumień, innymi poleceniami.

Co ze strumieniem błędów?

Strumienie wejścia i wyjścia, mamy wstępnie opanowane, więc czas na strumień błędów. Nim cokolwiek powiemy na temat jego używania, zajrzyjmy do pliku /usr/include/unistd.h. Zajdziemy tam między innymi wpis:
/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */
Jak widać, standardowe strumienie mają przypisane numery. Akurat w przypadku przekierowywania strumienia błędów konieczne jest posługiwanie się nimi. Sprawa na szczęście specjalnie się nie komplikuje. Przekierujmy strumień błędu na plik:
$ cat plik_testowy 2 > plik_bledy
Zawartość pliku testowego.
$ cat plik_bledy
$ cat plik_testowyXXX 2>plik_bledy
$ cat plik_bledy
cat: plik_testowyXXX: Nie ma takiego pliku ani katalogu
Gdy plik, który chcieliśmy wyświetlić, istniał, to plik z błędami, do którego przekierowaliśmy strumień błędów, był pusty. Jednak po powtórzeniu operacji dla pliku nieistniejącego, strumień błędów zamiast na ekran, trafił do pliku.

Zdarzają się również sytuacje, w których strumień błędów przekierować chcemy na strumień wyjścia (często zjawisko, przy użyciu funkcji exec() z PHP, gdy chcemy zobaczyć, komunikaty o błędach). Przekierowanie w postaci 2>1 niestety nie zadziała, a raczej zadziała, ale nie tak jak chcieliśmy. System zrozumie taki zapis, że ma strumień błędów wysłać do pliku o nazwie 1, a nie na strumień wyjściowy oznaczony tą liczbą. Poprawna składnia wygląda tak: 2>&1. W ten sposób wskazujemy systemowi, że nie chodzi nam o plik, a o strumień wyjścia.

$ cat plik_testowyXXX 2>&1
cat: plik_testowyXXX: Nie ma takiego pliku ani katalogu

Czy to już wszystko?

Myślę, że najważniejsze zagadnienia na temat standardowych strumieni zostały omówione. Na zakończenie przypomnę, że czasem bardzo użyteczne jest przekierowywanie strumieni wyjścia na /dev/null co znaczyć będzie mniej więcej tyle, że nie chcemy, by te strumienie gdziekolwiek zostały zapisane/wyświetlone.

Komentarze (2)

Imię:
Treść:
Administrator 2018-01-08 07:04:20
@Endriu, cieszę się, że artykuł mógł pomóc.
Endriu 2018-01-06 15:21:06
Prosto i zrozumiale. Thx