103.4 Урок 1
Сертифікат: |
LPIC-1 (101) |
---|---|
Версія: |
5.0 |
Розділ: |
103 GNU та команди Unix |
Тема: |
103.4 Використання потоків, каналів та перенаправлень |
Урок: |
1 з 2 |
Вступ
Усі комп’ютерні програми дотримуються одного і того ж загального принципу: дані, отримані з певного джерела, перетворюються, щоб отримати зрозумілий результат. У контексті оболонки Linux джерелом даних може бути локальний файл, віддалений файл, пристрій (наприклад, клавіатура) тощо. Вихідні дані програми зазвичай відображаються на екрані, але також часто вони зберігаються і в локальній файловій системі, відправляються на віддалений пристрій, відтворюються через аудіодинаміки тощо.
Операційні системи, натхненні Unix, такі як Linux, пропонують велику різноманітність методів введення/виведення. Зокрема, метод файлових дескрипторів дозволяє динамічно асоціювати цілі числа з каналами даних, щоб процес міг посилатися на них як на свої вхідні/вихідні потоки даних.
Стандартні процеси Linux мають три канали зв’язку, відкриті за замовчуванням: стандартний канал введення (найчастіше називається просто stdin), стандартний канал виведення (stdout) і стандартний канал помилок (stderr). Числові файлові дескриптори, призначені цим каналам: 0
для stdin, 1
для stdout і 2
для stderr. Канали зв’язку також доступні через спеціальні пристрої /dev/stdin
, /dev/stdout
та /dev/stderr
.
Ці три стандартні канали зв’язку дозволяють програмістам писати код, який зчитує і записує дані, не турбуючись про те, з якого медіа вони надходять або до яких вони спрямовуються. Наприклад, якщо програмі потрібен набір даних як вхід, вона може просто запитати дані зі стандартного введення, і все, що використовується як стандартний вхід, надасть ці дані. Аналогічно, найпростіший метод, який програма може використати для відображення результату, — це записати його до стандартного виведення. У стандартному сеансі оболонки клавіатура визначається як stdin, а екран монітора — як stdout і stderr.
Оболонка Bash має можливість перепризначати канали зв’язку під час завантаження програми. Це дозволяє, наприклад, замінити екран на файл у локальній файловій системі і використовувати його як stdout.
Перенаправлення
Перепризначення файлового дескриптора каналу в середовищі оболонки називається перенаправленням. Перенаправлення визначається спеціальним символом у командному рядку. Наприклад, щоб переспрямувати стандартне виведення процесу у файл, символ більше >
розміщується в кінці команди, за ним слідує шлях до файлу, який отримає переспрямований вихід:
$ cat /proc/cpuinfo >/tmp/cpu.txt
За замовчуванням перенаправляється лише вміст, що надходить до стандартного виведення (stdout). Це відбувається тому, що числове значення дескриптора файлу має бути вказано безпосередньо перед символом більше і, якщо не вказано, Bash перенаправляє стандартний вихід. Тому використання >
еквівалентно використанню 1>
(значення дескриптора файлу стандартного виведення дорівнює 1
).
Щоб зафіксувати вміст stderr, слід використовувати перенаправлення 2>
. Більшість програм командного рядка надсилають інформацію про налагодження та повідомлення про помилки на стандартний канал помилок. Можна, наприклад, зафіксувати повідомлення про помилку, викликане спробою прочитання файлу, що не існує:
$ cat /proc/cpu_info 2>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory
І stdout, і stderr перенаправляються до одного і того самого цільового об’єкта за допомогою &>
або >&
. Важливо не вставляти пробіли між амперсандом та знаком більше ніж, інакше Bash сприйме це як інструкцію для запуску процесу у фоновому режимі, а не для переспрямування.
Цільовим об’єктом має бути шлях до файлу, доступного для запису, наприклад /tmp/cpu.txt
, або дескриптор файлу для запису. Цільовий дескриптор представлений амперсандом, за яким слідує числове значення дескриптора файлу. Наприклад, 1>&2
перенаправляє stdout на stderr. Щоб зробити навпаки, stderr до stdout слід використовувати 2>&1
.
Хоча це не дуже корисно, враховуючи, що існує коротший спосіб виконати те саме завдання, можна перенаправити stderr на stdout, а потім перенаправити його до файлу. Наприклад, перенаправлення для запису як stderr, так і stdout до файлу з іменем log.txt
можна записати як >log.txt 2>&1
. Однак основна причина переспрямування stderr на stdout полягає в тому, щоб дозволити синтаксичний аналіз повідомлень про налагодження та помилки. Можна перенаправити стандартний вихід програми на стандартний вхід іншої програми, але неможливо безпосередньо перенаправити стандартний канал помилок на стандартний вхід іншої програми. Таким чином, повідомлення програми, надіслані на stderr, спочатку повинні бути перенаправлені на stdout, щоб їх прочитав stdin іншої програми.
Щоб просто нівелювати результат команди, його можна перенаправити до спеціального файлу /dev/null
. Наприклад, >log.txt 2>/dev/null
зберігає вміст stdout у файлі log.txt
і нівелює stderr. Файл /dev/null
доступний для запису будь-яким користувачем, але з нього не можна відновити дані, оскільки він ніде не зберігається.
Повідомлення про помилку відображається, якщо вказане цільове призначення недоступне для запису (якщо шлях вказує на каталог або файл лише для читання) і не внесено жодних змін до цільового об’єкту. Однак перенаправлення виведення перезаписує наявний цільовий об’єкт, доступний для запису, без запиту підтвердження. Файли перезаписуються перенаправленням виведення, якщо не ввімкнено параметр Bash noclobber
, що можна зробити для поточного сеансу за допомогою команди set -o noclobber
або set -C
:
$ set -o noclobber $ cat /proc/cpu_info 2>/tmp/error.txt -bash: /tmp/error.txt: cannot overwrite existing file
Щоб скасувати параметр noclobber
для поточного сеансу, запустіть set +o noclobber
або set +C
. Щоб зробити параметр noclobber
постійним, його необхідно включити до профілю Bash користувача або до загальносистемного профілю.
Навіть з увімкненим параметром noclobber
можна додавати перенаправлені дані до існуючого вмісту. Це досягається за допомогою переспрямування, записаного з двома символами більше >>
:
$ cat /proc/cpu_info 2>>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
У попередньому прикладі нове повідомлення про помилку було додано до наявного у файлі /tmp/error.txt
. Якщо файл ще не існує, він буде створений з новими даними.
Джерело даних стандартного введення процесу також можна перепризначити. Символ менше <
використовується для перенаправлення вмісту файлу до stdin процесу. У цьому випадку дані проходять справа наліво: передбачається, що перепризначений дескриптор дорівнює 0 зліва від символу менше, а джерело даних (шлях до файлу) має бути праворуч від символу менше. Команда uniq
, як і більшість утиліт командного рядка для обробки тексту, за замовчуванням приймає дані, надіслані на stdin:
$ uniq -c </tmp/error.txt 2 cat: /proc/cpu_info: No such file or directory
Опція -c
змушує uniq
відображати, скільки разів у тексті з’являється повторений рядок. Оскільки числове значення дескриптора перенаправленого файлу було опущено, команда прикладу еквівалентна uniq -c 0</tmp/error.txt
. Використання дескриптора файлу, відмінного від 0
, у вхідному переспрямуванні має сенс лише в певних контекстах, оскільки програма може запитувати дані в дескрипторах файлу 3
, 4
тощо. Справді, програми можуть використовувати будь-яке ціле число вище 2 як нові дескриптори файлу для введення/виведення даних. Наприклад, наступний код мовою C зчитує дані з дескриптора файлу 3
і просто реплікує їх до дескриптора файлу 4
:
Note
|
Програма повинна правильно обробляти такі файлові дескриптори, інакше вона може спробувати виконати недійсну операцію читання або запису та завершити роботу. |
#include <stdio.h> int main(int argc, char **argv){ FILE *fd_3, *fd_4; // Open file descriptor 3 fd_3 = fdopen(3, "r"); // Open file descriptor 4 fd_4 = fdopen(4, "w"); // Read from file descriptor 3 char buf[32]; while ( fgets(buf, 32, fd_3) != NULL ){ // Write to file descriptor 4 fprintf(fd_4, "%s", buf); } // Close both file descriptors fclose(fd_3); fclose(fd_4); }
Щоб перевірити код вище, збережіть його як fd.c
і скомпілюйте його за допомогою gcc -o fd fd.c
. Для цієї програми потрібні дескриптори файлів 3 і 4, щоб вона могли читати та записувати до них. Як приклад, раніше створений файл /tmp/error.txt
можна використовувати як джерело для дескриптора файлу 3
, а дескриптор файлу 4
можна перенаправити до стандартного виведення:
$ ./fd 3</tmp/error.txt 4>&1 cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
З точки зору програміста, використання файлових дескрипторів дозволяє уникнути розбору параметрів і шляхів до файлової системи. Один і той самий дескриптор файлу можна навіть використовувати як вхід та як вихід. У цьому випадку дескриптор файлу визначається в командному рядку як символами менше та більше, як у 3<>/tmp/error.txt
.
Here Document та Here String
Інший спосіб переспрямування введення використовує методи Here document і Here string. Переспрямування Here document дозволяє ввести багаторядковий текст, який буде використовуватися як переспрямований вміст. Два символи менше <<
вказують на переспрямування Here document:
$ wc -c <<EOF > How many characters > in this Here document? > EOF 43
Праворуч від двох символів менше <<
є кінцевий термін EOF
. Режим вставки завершиться, як тільки буде введено рядок, що містить лише кінцевий термін. Як кінцевий термін можна використовувати будь-який інший термін, але між символом менше і кінцевим терміном важливо не ставити пробіли. У наведеному вище прикладі два рядки тексту були надіслані на stdin команди wc -c
, який відображає кількість символів. Як і в разі перенаправлень вхідних даних для файлів, stdin (дескриптор файлу 0
) передбачається, якщо дескриптор переспрямованого файлу опущено.
Метод Here string дуже схожий на метод Here document, але працює лише для одного рядка:
$ wc -c <<<"How many characters in this Here string?" 41
У цьому прикладі рядок праворуч від трьох знаків менше надсилається на stdin wc -c
, який підраховує кількість символів. Рядки, що містять пробіли, мають бути в лапках, інакше лише перше слово буде використано як Here string, а інші будуть передані команді в якості аргументів.
Вправи до посібника
-
Окрім текстових файлів, команда
cat
також може працювати з двійковими даними, такими як надсилання вмісту блочного пристрою до файлу. Використовуючи перенаправлення, якcat
може відправити вміст пристрою/dev/sdc
до файлуsdc.img
у поточному каталозі? -
Як називається стандартний канал, перенаправлений командою
date 1> now.txt
? -
Після спроби перезаписати файл за допомогою переспрямування, користувач отримує повідомлення про помилку, що ввімкнено параметр
noclobber
. Як можна деактивувати параметрnoclobber
для поточного сеансу? -
Яким буде результат команди
cat <<.>/dev/stdout
?
Дослідницькі вправи
-
Команда
cat /proc/cpu_info
відображає повідомлення про помилку, оскільки/proc/cpu_info
не існує. Куди командаcat /proc/cpu_info 2>1
перенаправляє повідомлення про помилку? -
Чи можна буде відкинути вміст, надісланий до
/dev/null
, якщо параметрnoclobber
увімкнено для поточного сеансу оболонки? -
Як можна було б перенаправити вміст змінної
$USER
до stdin командиsha1sum
без використанняecho
? -
Ядро Linux зберігає символьні посилання в
/proc/PID/fd/
на кожен файл, відкритий процесом, де PID є ідентифікаційним номером відповідного процесу. Як системний адміністратор може використати цей каталог, щоб перевірити розташування файлів журналів, відкритихnginx
, якщо його PID дорівнює1234
? -
Можна виконувати арифметичні обчислення, використовуючи лише вбудовані команди оболонки, але обчислення з плаваючою комою вимагають спеціальних програм, наприклад
bc
(basic calculator). Дляbc
можна навіть вказати кількість десяткових знаків за допомогою параметраscale
. Однакbc
приймає операції лише за допомогою стандартного введення, зазвичай введення відбувається в інтерактивному режимі. Використовуючи Here string, як можна операцію з плаваючою комоюscale=6; 1/3
надіслати на стандартний вхідbc
?
Підсумки
Цей урок охоплює методи запуску програми з перенаправленням її стандартних каналів зв’язку. Процеси Linux використовують ці стандартні канали як загальні дескриптори файлів для читання та запису даних, що дає змогу довільно змінювати їх на файли чи пристрої. В уроці розглядаються наступні теми:
-
Що таке дескриптори файлів і роль, яку вони відіграють у Linux.
-
Стандартні канали зв’язку кожного процесу: stdin, stdout та stderr.
-
Як правильно виконати команду, використовуючи переспрямування даних, як для введення, так і для виведення.
-
Як використовувати Here Documents і Here Strings у переспрямуваннях введення.
Розглянуті команди та процедури:
-
Оператори переспрямування:
>
,<
,>>
,<<
,<<<
. -
Команди
cat
,set
,uniq
таwc
.
Відповіді на вправи до посібника
-
Окрім текстових файлів, команда
cat
також може працювати з двійковими даними, такими як надсилання вмісту блочного пристрою до файлу. Використовуючи перенаправлення, якcat
може відправити вміст пристрою/dev/sdc
до файлуsdc.img
у поточному каталозі?$ cat /dev/sdc > sdc.img
-
Як називається стандартний канал, перенаправлений командою
date 1> now.txt
?Стандартний вихід або stdout
-
Після спроби перезаписати файл за допомогою переспрямування, користувач отримує повідомлення про помилку, що ввімкнено параметр
noclobber
. Як можна деактивувати параметрnoclobber
для поточного сеансу?set +C
абоset +o noclobber
-
Яким буде результат команди
cat <<.>/dev/stdout
?Bash перейде в режим введення Heredoc, а потім вийде, коли в рядку з’явиться крапка. Введений текст буде перенаправлено на стандартний вихід (виведення на екран).
Відповіді до дослідницьких вправ
-
Команда
cat /proc/cpu_info
відображає повідомлення про помилку, оскільки/proc/cpu_info
не існує. Куди командаcat /proc/cpu_info 2>1
перенаправляє повідомлення про помилку?До файлу з іменем
1
у поточному каталозі. -
Чи можна буде відкинути вміст, надісланий до
/dev/null
, якщо параметрnoclobber
увімкнено для поточного сеансу оболонки?Так.
/dev/null
– це спеціальний файл, на який не впливаєnoclobber
. -
Як можна було б перенаправити вміст змінної
$USER
до stdin командиsha1sum
без використанняecho
?$ sha1sum <<<$USER
-
Ядро Linux зберігає символьні посилання в
/proc/PID/fd/
на кожен файл, відкритий процесом, де PID є ідентифікаційним номером відповідного процесу. Як системний адміністратор може використати цей каталог, щоб перевірити розташування файлів журналів, відкритихnginx
, якщо його PID дорівнює1234
?За допомогою команди
ls -l /proc/1234/fd
, яка відобразить цільові об’єкти кожного символьного посилання в каталозі. -
Можна виконувати арифметичні обчислення, використовуючи лише вбудовані команди оболонки, але обчислення з плаваючою комою вимагають спеціальних програм, наприклад
bc
(basic calculator). Дляbc
можна навіть вказати кількість десяткових знаків за допомогою параметраscale
. Однакbc
приймає операції лише за допомогою стандартного введення, зазвичай введення відбувається в інтерактивному режимі. Використовуючи Here string, як можна операцію з плаваючою комоюscale=6; 1/3
надіслати на стандартний вхідbc
?$ bc <<<"scale=6; 1/3"