103.4 Урок 2
Сертифікат: |
LPIC-1 (101) |
---|---|
Версія: |
5.0 |
Розділ: |
103 GNU та команди Unix |
Тема: |
103.4 Використання потоків, каналів та перенаправлень |
Урок: |
2 з 2 |
Вступ
Один з аспектів філософії Unix стверджує, що кожна програма повинна мати конкретну мету і не повинна намагатися виконувати функції, які до неї не відносяться. Але збереження простоти не означає досягнення менш складних результатів, тому що різні програми можна об’єднати разом, щоб отримати комбінований результат. Символ вертикальної смуги |
, також відомий як символ конвеєр, може використовуватися для створення конвеєра, який з’єднує вихідні дані однієї програми безпосередньо з вхідними даними іншої, тоді як командне заміщення дозволяє зберігати вихідні дані програми у змінній або використовувати їх безпосередньо як аргумент для іншої команди.
Конвеєри
На відміну від перенаправлень, за допомогою конвеєрів дані проходять зліва направо в командному рядку, а цільовим об’єктом є інший процес, а не шлях у файловій системі, дескриптор файлу або Here document. Символ вертикальної лінії |
вказує оболонці запустити всі різні команди одночасно і підключити вихід попередньої команди до входу наступної команди зліва направо. Наприклад, замість використання перенаправлень вміст файлу /proc/cpuinfo
, надісланого до стандартного виводу cat
, можна передати на stdin wc
за допомогою такої команди:
$ cat /proc/cpuinfo | wc 208 1184 6096
У разі відсутності шляху до файлу, wc
підраховує кількість рядків, слів і символів, які він отримує на своєму stdin, як у прикладі. У складеній команді може бути багато конвеєрів. У наступному прикладі використовуються два конвеєри:
$ cat /proc/cpuinfo | grep 'model name' | uniq model name : Intel(R) Xeon(R) CPU X5355 @ 2.66GHz
Вміст файлу /proc/cpuinfo
, створеного cat /proc/cpuinfo
, був переданий команді grep 'model name'
, яка потім вибирає лише рядки, що містять термін model name
. Комп’ютер, на якому виконується приклад, має багато процесорів, тому є рядки з model name
, які повторюються. Останній конвеєр з’єднує grep 'model name'
з uniq
, який відповідає за пропуск будь-якого рядку, рівного попередньому.
Конвеєри можна комбінувати з перенаправленнями в одному командному рядку. Попередній приклад можна переписати простіше:
$ grep 'model name' </proc/cpuinfo | uniq model name : Intel(R) Xeon(R) CPU X5355 @ 2.66GHz
Перенаправлення введення для grep
не є строго необхідним, оскільки grep
приймає шлях до файлу як аргумент, але приклад демонструє, як побудувати такі комбіновані команди.
Конвеєри та перенаправлення є ексклюзивними, тобто одне джерело можна зіставити лише з одним цільовим об’єктом. Тим не менш, можна перенаправити вихідні дані до файлу і все одно бачити їх на екрані за допомогою програми tee
. Для цього перша програма надсилає свої вихідні дані на stdin tee
, а останньому надається ім’я файлу для зберігання даних:
$ grep 'model name' </proc/cpuinfo | uniq | tee cpu_model.txt model name : Intel(R) Xeon(R) CPU X5355 @ 2.66GHz $ cat cpu_model.txt model name : Intel(R) Xeon(R) CPU X5355 @ 2.66GHz
Результат останньої програми в ланцюжку, згенерований uniq
, відображається та зберігається у файлі cpu_model.txt
. Щоб не перезаписувати вміст зазначеного файлу, а додавати до нього дані, параметр -a
має бути наданий у tee
.
Лише стандартний вихід процесу фіксується конвеєром. Скажімо, ви повинні пройти тривалий процес компіляції на екрані і в той же час зберегти стандартний вихід і стандартну помилку до файлу для подальшої перевірки. Якщо припустити, що у вашому поточному каталозі немає файлу Makefile, така команда виведе помилку:
$ make | tee log.txt make: *** No targets specified and no makefile found. Stop.
Незважаючи на те, що повідомлення про помилку відображалося на екрані, повідомлення про помилку, створене make
, не було перехоплено tee
, а файл log.txt був створений порожнім. Перед тим, як канал зможе захопити stderr, необхідно виконати перенаправлення:
$ make 2>&1 | tee log.txt make: *** No targets specified and no makefile found. Stop. $ cat log.txt make: *** No targets specified and no makefile found. Stop.
У цьому прикладі stderr make
був перенаправлений до стандартного виведення, тому tee
зміг захопити його за допомогою конвеєру, відобразити на екрані та зберегти до файлу log.txt
. У таких випадках може бути корисно зберегти повідомлення про помилки для подальшої перевірки.
Командне заміщення
Іншим методом отримання результату команди є командне заміщення. Поміщаючи команду в зворотні лапки, Bash замінює її стандартним виводом. У наступному прикладі показано, як використовувати стандартний вихід програми як аргумент для іншої програми:
$ mkdir `date +%Y-%m-%d` $ ls 2019-09-05
Результат програми date
, поточна дата у форматі year-month-day, використано як аргумент для створення каталогу з mkdir
. Ідентичний результат отримаємо, якщо використовувати $()
замість зворотних лапок:
$ rmdir 2019-09-05 $ mkdir $(date +%Y-%m-%d) $ ls 2019-09-05
Цей же метод можна використовувати для збереження результату команди до змінної:
$ OS=`uname -o` $ echo $OS GNU/Linux
Команда uname -o
виводить загальне ім’я поточної операційної системи, яке зберігається у змінній сеансу OS
. Збереження виведення команди у змінній дуже корисно в сценаріях, завдяки чому можна зберігати та оцінювати дані багатьма різними способами.
Залежно від результату, згенерованого заміненою командою, заміна вбудованої команди може бути неприйнятною. Більш складний метод використання результатів програми як аргументу іншої програми використовує проміжний елемент, який називається xargs
. Програма xargs
використовує вміст, який вона отримує через stdin, щоб запустити задану команду з цілим вмістом як аргументом. У наступному прикладі показано xargs
, що запускає програму identify
з аргументами, наданими програмою find
:
$ find /usr/share/icons -name 'debian*' | xargs identify -format "%f: %wx%h\n" debian-swirl.svg: 48x48 debian-swirl.png: 22x22 debian-swirl.png: 32x32 debian-swirl.png: 256x256 debian-swirl.png: 48x48 debian-swirl.png: 16x16 debian-swirl.png: 24x24 debian-swirl.svg: 48x48
Програма identify
є частиною ImageMagick, набору інструментів командного рядка для перевірки, перетворення та редагування більшості типів файлів зображень. У прикладі xargs
взяв усі шляхи, зазначені в find
, і помістив їх як аргументи для програми identify
, яка потім показує інформацію для кожного файлу, відформатовану відповідно до параметра -format
. Файли, знайдені за допомогою find
у прикладі, є зображеннями, що містять логотип дистрибутива у файловій системі Debian. -format
є параметром для identify
, а не для xargs
.
Опція -n 1
вимагає, щоб xargs
виконував дану команду лише з одним аргументом за раз. У нашому прикладі, замість того, щоб передавати всі шляхи, знайдені за допомогою find
, як список аргументів для identify
, використання xargs -n 1
виконає команду identify
для кожного шляху окремо. Використання -n 2
виконає identify
з двома шляхами в якості аргументів, -n 3
з трьома шляхами тощо. Аналогічно, коли xargs
обробляє багаторядковий вміст, як у випадку з введенням, наданим find
, параметр -L
можна використовувати, щоб обмежити кількість рядків, які будуть використовуватися як аргументи під час виконання команди.
Note
|
Використання |
Якщо шляхи містять пробіли, важливо запустити find
з опцією -print0
. Цей параметр наказує find
використовувати нульовий символ між записами, щоб список можна було правильно проаналізувати за допомогою xargs
(вихідні дані були опущені):
$ find . -name '*avi' -print0 -o -name '*mp4' -print0 -o -name '*mkv' -print0 | xargs -0 du | sort -n
Параметр -0
повідомляє xargs
, що нульовий символ має використовуватися як роздільник. Таким чином шляхи до файлів, задані find
, аналізуються правильно, навіть якщо в них є порожні або інші спеціальні символи. Попередній приклад показує, як використовувати команду du
, щоб дізнатися про використання диску кожним знайденим файлом, а потім відсортувати результати за розміром. Вихідні дані було опущено для стислості. Зверніть увагу, що для кожного критерію пошуку необхідно розмістити параметр -print0
для find
.
За замовчуванням xargs
розміщує аргументи виконаної команди останніми. Щоб змінити цю поведінку, слід використовувати параметр -I
:
$ find . -mindepth 2 -name '*avi' -print0 -o -name '*mp4' -print0 -o -name '*mkv' -print0 | xargs -0 -I PATH mv PATH ./
В останньому прикладі кожен файл, знайдений за допомогою find
, переміщується до поточного каталогу. Оскільки вихідний шлях(и) має бути повідомлений mv
перед цільовим шляхом, термін заміни надається для опції -I
із xargs
, який потім відповідно розміщується поруч із mv
. Використовуючи нульовий символ як роздільник, не потрібно брати термін заміни в лапки.
Вправи до посібника
-
Зручно зберігати дату виконання дій, що виконуються автоматизованими скриптами. Команда
date +%Y-%m-%d
показує поточну дату у форматі year-month-day. Як результат такої команди може бути збережений у змінній оболонки під назвоюTODAY
за допомогою командного заміщення? -
Використовуючи команду
echo
, як можна надіслати вміст змінноїTODAY
на стандартний вхід командиsed s/-/./g
? -
Як можна використовувати вихідні дані команди
date +%Y-%m-%d
як Here string для командиsed s/-/./g
? -
Команда
convert image.jpeg -resize 25% small/image.jpeg
створює меншу версіюimage.jpeg
і розміщує отримане зображення у файлі з такою ж назвою у підкаталозіsmall
. Використовуючиxargs
, як можна виконати ту саму команду для кожного зображення, що перелічено у файліfilelist.txt
?
Дослідницькі вправи
-
Проста програма резервного копіювання періодично створює образ розділу
/dev/sda1
зdd < /dev/sda1 > sda1.img
. Щоб виконувати майбутні перевірки цілісності даних, програма також генерує хеш SHA1 файлу зsha1sum < sda1.img > sda1.sha1
. Як ці дві команди об’єднати в одну, використовуючи конвеєри та командуtee
? -
Команда
tar
використовується для архівування багатьох файлів в один файл, зберігаючи структуру каталогів. Параметр-T
дозволяє вказати файл, що містить шляхи для архівування. Наприклад,find /etc -type f | tar -cJ -f /srv/backup/etc.tar.xz -T -
створює стиснений tar-файлetc.tar.xz
зі списку, наданого командоюfind
(опція-T -
вказує на стандартне введення як список шляхів). Щоб уникнути можливих помилок аналізу через шляхи, що містять пробіли, які параметри команд мають бути присутніми дляfind
іtar
? -
Замість того, щоб відкривати новий сеанс віддаленої оболонки, команда
ssh
може просто виконати команду, зазначену як її аргумент:ssh user@storage "remote command"
. Враховуючи, щоssh
також дозволяє перенаправляти стандартний вихід локальної програми на стандартний вхід віддаленої програми, як командаcat
може передати локальний файл з ім’ямetc.tar.gz
у/srv/backup /etc.tar.gz
наuser@storage
черезssh
?
Підсумки
Цей урок охоплює традиційні міжпроцесні комунікації, які використовуються в Linux. Конвеєр команд створює односторонній канал зв’язку між двома процесами, а командне заміщення дозволяє зберігати результат процесу у змінній оболонки. В уроці розглядаються такі питання:
-
Як конвеєри можна використовувати для потокової передачі виводу процесу на вхід іншого процесу.
-
Призначення команд
tee
таxargs
. -
Як зафіксувати результат процесу за допомогою командного заміщення, зберегти його у змінній або використати його безпосередньо як параметр для іншої команди.
Розглянуті команди та процедури:
-
Конвеєр команд за допомогою
|
. -
Командне заміщення за допомогою зворотних лапок і
$()
. -
Команди
tee
,xargs
таfind
.
Відповіді на вправи до посібника
-
Зручно зберігати дату виконання дій, що виконуються автоматизованими скриптами. Команда
date +%Y-%m-%d
показує поточну дату у форматі year-month-day. Як результат такої команди може бути збережений у змінній оболонки під назвоюTODAY
за допомогою командного заміщення?$ TODAY=`date +%Y-%m-%d`
or
$ TODAY=$(date +%Y-%m-%d)
-
Використовуючи команду
echo
, як можна надіслати вміст змінноїTODAY
на стандартний вхід командиsed s/-/./g
?$ echo $TODAY | sed s/-/./g
-
Як можна використовувати вихідні дані команди
date +%Y-%m-%d
як Here string для командиsed s/-/./g
?$ sed s/-/./g <<< `date +%Y-%m-%d`
або
$ sed s/-/./g <<< $(date +%Y-%m-%d)
-
Команда
convert image.jpeg -resize 25% small/image.jpeg
створює меншу версіюimage.jpeg
і розміщує отримане зображення у файлі з такою ж назвою у підкаталозіsmall
. Використовуючиxargs
, як можна виконати ту саму команду для кожного зображення, що перелічено у файліfilelist.txt
?$ xargs -I IMG convert IMG -resize 25% small/IMG < filelist.txt
або
$ cat filelist.txt | xargs -I IMG convert IMG -resize 25% small/IMG
Відповіді до дослідницьких вправ
-
Проста програма резервного копіювання періодично створює образ розділу
/dev/sda1
зdd < /dev/sda1 > sda1.img
. Щоб виконувати майбутні перевірки цілісності даних, програма також генерує хеш SHA1 файлу зsha1sum < sda1.img > sda1.sha1
. Як ці дві команди об’єднати в одну, використовуючи конвеєри та командуtee
?# dd < /dev/sda1 | tee sda1.img | sha1sum > sda1.sha1
-
Команда
tar
використовується для архівування багатьох файлів в один файл, зберігаючи структуру каталогів. Параметр-T
дозволяє вказати файл, що містить шляхи для архівування. Наприклад,find /etc -type f | tar -cJ -f /srv/backup/etc.tar.xz -T -
створює стиснений tar-файлetc.tar.xz
зі списку, наданого командоюfind
(опція-T -
вказує на стандартне введення як список шляхів). Щоб уникнути можливих помилок аналізу через шляхи, що містять пробіли, які параметри команд мають бути присутніми дляfind
іtar
?Опції
-print0
та--null
:$ find /etc -type f -print0 | tar -cJ -f /srv/backup/etc.tar.xz --null -T -
-
Замість того, щоб відкривати новий сеанс віддаленої оболонки, команда
ssh
може просто виконати команду, зазначену як її аргумент:ssh user@storage "remote command"
. Враховуючи, щоssh
також дозволяє перенаправляти стандартний вихід локальної програми на стандартний вхід віддаленої програми, як командаcat
може передати локальний файл з ім’ямetc.tar.gz
у/srv/backup /etc.tar.gz
наuser@storage
черезssh
?$ cat etc.tar.gz | ssh user@storage "cat > /srv/backup/etc.tar.gz"
або
$ ssh user@storage "cat > /srv/backup/etc.tar.gz" < etc.tar.gz