Лабораторна робота №6
Командний інтерпретатор bash. Основи написання сценаріїв (скриптів)
Мета роботи: Освоїти командний інтерпретатор bash. Набути початкових навичок написання командних файлів (скриптів).
6.1 Стислі теоретичні відомості
Командний інтерпретатор (оболонка, shell) є інтерфейсом користувача в UNIX-системі. Командний інтерпретатор - це просто програма, яка дозволяє системі розуміти команди користувача (звідси назва), і дає йому можливість створювати зручне для себе середовище роботи в UNIX. Як правило, дії інтерпретатора не помітні користувачеві, вони відбуваються як наче за кулісами.
Командний інтерпретатор можна розглядати як захисну оболонку ядра системи. Як відомо, при запуску системи ядро завантажується в пам'ять і виконує багато низькорівневих системних функцій. Ядро регулює роботу процесора, здійснює і регулює протікання процесів, відповідає за ввід/вивід даних. Можливе існування тільки одного ядра. Інструкції ядра складні, громіздкі, і сильно прив'язані до апаратних засобів. Працювати на мові такого рівня дуже важко, тому і виникло багато командних інтерпретаторів (оболонок). Вони захищають користувача від складності ядра, а ядро - від некомпетентності користувача. Користувач дає команди інтерпретатору, той в свою чергу перекладає їх на системну мову і передає ядру.
Функціями якого завгодно інтерпретатора є:
- інтерпретація командного рядка;
- ініціалізація програм;
- перенаправлення потоків вводу/виводу;
- організація конвеєрного виконання програм (каналів);
- підстановка імен файлів;
- робота зі змінними;
- контроль за середовищем;
- надання засобів керування задачами;
- програмування.
В оболонці визначаються змінні, які керують поведінкою Вашої сесії роботи з UNIX. Вони повідомляють системі, який каталог вважати Вашим робочим каталогом, в якому файлі зберігати вхідну електронну пошту та ін. Деякі змінні попередньо установлюються операційною системою, інші можна визначити самому в файлах початкового завантаження.
В командних інтерпретаторах передбачені спеціальні вбудовані команди, які можуть використовуватися для побудови командних файлів. Командний файл (скрипт, сценарій) - це текстовий файл, що містить UNIX-команди (аналог bat-файлів в DOS).
Звичайно з тою, або іншою ОС поставляються кілька оболонок. Як правило, програмісти працюють в одній оболонці, більш гнучкою і зручною для користування (наприклад csh або bash), а командні файли пишуть для іншої, більш простої (такої як Bourne). Оболонка, яка буде використовуватися по замовченню при реєстрації, та інша особиста інформація визначається в файлі /etc/passwd для кожного користувача окремо. Користувач може в який завгодно момент змінити вибір оболонки, що використовується при реєстрації (команда chsh). Основними оболонками різних версій UNIX є:
Bourne Shell sh
Korn Shell ksh
C Shell csh
Bourne Again Shell bash
Public Domain Korn Shell pdksh
A Shell ash
Tcl Shell tclsh
X-Windows Shell wish
Remote Shell rsh
Деякі оболонки можуть бути присутніми в одній версії ОС і не бути представлені в іншій. Іноді оболонки сполучаються. Так, в деяких версіях Linux sh і bash - це одна і та ж програма (sh і bash є посиланнями на один і той ж файл). Незалежно від того, який командний інтерпретатор використовується, його основною задачею є надання інтерфейсу для користувача.
6.1.1 Командний інтерпретатор bash (bash)
Bash shell - один з найбільш популярних командних інтерпретаторів в системі Linux. Ця оболонка була розроблена на основі оболонок Bourne Shell і C Shell з додаванням функцій, що помітно полегшують роботу з Linux. Виклик оболонки відбувається по команді bash (файл /bin/bash або /usr/bin/bash). Показником того, що ви знаходитесь в bash, є системний запит "$".
6.1.2 Стандартні командні файли
Кожен раз при реєстрації користувача в системі виконується командний файл .bash_profile (аналог autoexec.bat і config.sys в DOS), який знаходиться в його домашньому каталозі. Файл .bash_profile являє собою файл ініціалізації командного інтерпретатора bash. Він виконується автоматично при кожному завантаженні оболонки. Даний файл містить команди, які визначають спеціальні змінні середовища, як системні, так і користувачеві. Розглянемо приклад стандартного файлу .bash_profile:
# .bash_profile (1)
# Get the aliases and functions (2)
if [ -f ~/.bashrc ]; then (3)
. ~/.bashrc (4)
fi (5)
# User specific environment and startup programs (6)
PATH=$PATH:$HOME/bin (7)
ENV=$HOME/.bashrc (8)
USERNAME="" (9)
export USERNAME ENV PATH (10)
Рядки, що починаються зі знака # (1, 2, 6), трактуються як коментарі. Їх вміст, як правило, ігнорується.
В рядку 3 перевіряється, чи існує в домашньому каталозі користувача файл .bashrc. Якщо такий присутній, то виконується гілка умови then (рядок 4) - файл .bashrc запускається на виконання. Рядок 5 - кінець конструкції if-then.
Рядки 7-9 визначають змінні середовища. Зверніть увагу на те, що змінні PATH і HOME - це системні змінні, які система попередньо визначила сама. В даному файлі значення змінної PATH модифікується (розширюється). Спеціальні змінні та режими оболонки bash наведені в Додатку В.
Спеціальні змінні, крім усього іншого, потрібно експортувати з допомогою команди export. Це робиться для того, щоб вони стали доступними для всіх можливих вторинних оболонок. Однією командою export можна експортувати кілька змінних, перерахувавши їх в командному рядку як аргументи (рядок 10).
Ще одним файлом ініціалізації оболонки bash є .bashrc. Він виконується кожен раз, коли користувач входить в оболонку. Цей файл також запускається кожен раз при запуску якого завгодно командного файлу (скрипта). В .bashrc звичайно містяться визначення псевдонімів і змінних, які служать для включення тих чи інших функцій командного інтерпретатора. Приклад файлу .bashrc наведено нижче:
# .bashrc (1)
# User specific aliases and functions (2)
# Source global definitions (3)
if [ -f /etc/bashrc ]; then (4)
. /etc/bashrc (5)
fi (6)
set -o noclobber (7)
alias l='/bin/ls -al' (8)
Як і в попередньому прикладі, в файлі використовується конструкція if-then (рядка 4-5). В ній наведене посилання на стандартний файл завантаження, єдиний для всіх користувачів системи - /etc/bashrc.
В рядку 7 установлюється режим noclobber. Він охороняє існуючі файли від запису поверх них переадресованої вхідної інформації. Можливі ситуації, коли в якості імені файлу, в який переадресується вивід, користувач може випадково вказати ім'я існуючого файлу. Якщо режим noclobber установлено, то при переадресації вхідної інформації в уже існуючий файл цей файл не буде замінено стандартнім вихідним потоком. Файл-оригінал збережеться.
Іноді при роботі доводиться часто використовувати одну і ту ж команду або послідовність команд. Цю проблему можна вирішити, створивши командний файл і вказавши каталог, в якому він знаходиться, в змінній оточення PATH. Однак не завжди раціонально зберігати окремий скрипт для кожної команди, що часто застосовується (надто багато файлів малої довжини). Для цього існують псевдоніми (aliases). Наприклад, однією з найчастіше використовуваних команд є ls, але формат вихідних даних незручний (якщо команда запущена без опцій). Набагато зручніше і наочніше виглядає результат роботи команди /bin/ls -al. Але це неможлива розкіш - вводити такий довгий рядок кожен раз при необхідності довгого лістингу каталогу. В рядку 8 ми створюємо псевдонім. Псевдонім працює як макрос, який перетворює його в команду.
Крім файлів .bash_profile і .bashrc в домашньому каталозі користувача, як правило, ведеться протокол команд, введених користувачем раніше (.bash_history), і скрипт виходу з системи (.bash_logout).
6.1.3 Робота командного інтерпретатора в інтерактивному режимі
Коли користувач вводить команду на місці запиту ($), він передає її на обробку командному інтерпретатору. Інтерпретатор сприймає рядок команди як послідовність символів, в кінці якої знаходиться "повернення каретки" (Enter). Оболонка сприймає кілька типів команд: команди Linux системи, вбудовані команди інтерпретатора, команди, визначені користувачем, і команди-псевдоніми.
На свій розсуд, користувач може вводити команди по черзі, за принципом "один рядок - одна команда". Однак оболонка не накладає в цьому плані жодних обмежень. Дозволяється вводити по кілька команд в одному рядку, розділяючи їх крапкою з комою. Можливий випадок, коли команда не вміщується на один рядок - тоді можна сховати "повернення каретки" від оболонки, поставивши перед ним зворотну риску "\", і продовжувати ввід команди на наступному рядку. Таким чином, всі нижче приведені команди приведуть до однакових результатів:
1)
$ who; ps; echo JUNK MESSAGE
... (результат роботи who)
... (результат роботи ps)
JUNK MESSAGE (результат роботи echo)
2)
$ who
... (результат роботи who)
$ ps
... (результат роботи ps)
$ echo JUNK MESSAGE
JUNK MESSAGE (результат роботи echo)
3)
$ who; ps; echo JUNK \
>MESSAGE
... (результат роботи who)
... (результат роботи ps)
JUNK MESSAGE (результат роботи echo)
Команда (або група команд), поміщена в дужки, виконується у вторинній оболонці (підоболонці). Підоболонка - це нова оболонка, що викликається поверх старої (первинної) оболонки. При цьому виконавчі команди вносять зміни тільки в цю підоболонку, не змінюючи параметрів первинного командного інтерпретатора (змінних, поточного каталогу і та ін.). Порівняйте:
[stud@localhost stud]$ cd /home
[stud@localhost home]$
^^^^
і
[stud@localhost stud]$ (cd /home)
[stud@localhost stud]$
^^^^
В другому випадку команда зміни поточного каталогу (cd /home) виконувалась в підоболонці, тобто поточний каталог змінився тільки для цієї підоболонки. Після виконання команди існування підоболонки закінчилось, і керування перейшло назад в первинну оболонку. Поточний каталог первинної оболонки залишився старим.
Іноді необхідно, щоб вихідні дані однієї команди слугували параметром (але не вхідним потоком!) для іншої. Для цього команду поміщають в зворотні лапки і ставлять на місці параметрів для зовнішньої команди. Наприклад:
$ elm `whoami`
Команда whoami повертає ім'я, під яким користувач зареєструвався в системі. Це ім'я підставляється в командний рядок в якості параметра для команди elm (посилка поштового повідомлення). Таким чином користувач посилає самому собі e-mail.
Оболонка bash веде історію введених з консолі команд. Проглянути її можна по команді history. Крім того, введені команди можна використовувати повторно. Найпростішими прикладами використання введених раніше команд є !! та !n.
!! остання введена з консолі команда (рядок)
!n n-а команда історії
!-n n-а команда історії, взятої в зворотному порядку (!-1 еквівалентно !!)
!str найостанніша команда з історії, що починається рядком "str"
Вихід з оболонки здійснюється по команді exit [expr]. Ця команда забезпечує вихід з поточної оболонки (командного інтерпретатора) з кодом expr. Вихід з оболонки також здійснюється при досягненні символу "кінець файлу" (Ctrl-D).
6.1.4 Командний інтерпретатор як процес
Спробуємо розглянути командний інтерпретатор більш формально. Будучи звичайною виконуваною програмою, оболонка є процесом. Як і кожен процес в системі UNIX, командний інтерпретатор має унікальний номер процесу, свої вхідні і вихідні потоки даних і всі інші атрибути процесу. Коли інтерпретатор виконується в інтерактивному режимі, вхідний і вихідний потоки асоційовані з терміналом - користувач вводить команди з клавіатури, результат виводиться на екран. Наприклад, в деякому каталозі знаходиться файл script з таким вмістом.
ps
echo end of script
Нагадаємо, що команда echo виводить повідомлення в стандартний вихідний файл (потік). Команда ps друкує в вихідний файл інформацію про процеси, які запустив користувач. Запустимо скрипт на виконання: по команді . (крапка) виконується командний файл, що передається як параметр.
[stud@localhost stud]$ . script
PID TTY STAT TIME COMMAND
269 1 S 0:00 /bin/login -- stud
270 1 S 0:00 –bash
360 1 R 0:00 ps
end of script
[stud@localhost stud]$
Як бачимо з результатів, на момент виконання команди ps з командного файлу script, в системі виконувалось одночасно три процеси, якими володіє користувач stud. Перший (під номером 269) - це процес підключення до системи (реєстрація). Другий (270) - це командний інтерпретатор. Третій (360) - це безпосередньо команда ps.
Скористуємося механізмом перенаправлення потоків:
[stud@localhost stud]$ bash < script > outfile
[stud@localhost stud]$ cat outfile
PID TTY STAT TIME COMMAND
269 1 S 0:00 /bin/login -- stud
270 1 S 0:00 -bash
361 1 S 0:00 bash
362 1 R 0:00 ps
end of script
[stud@localhost stud]$
Опишемо ситуацію, що відбулася. Користувач stud, знаходячись в оболонці bash (процес 270), запускає нову оболонку bash (процес 361), вторинну по відношенню до першої (первинна помічена дефісом). Вхідним потоком нової оболонки є не термінал, а файл. Результат роботи перенаправлюєтся в інший файл. Команди файлу script, зокрема, команда ps (процес 362), виконуються в новій оболонці. Результат був би аналогічний, якщо б користувач просто викликав підоболонку, а потім послідовно ввів з клавіатури команди ps, echo і символ кінця файлу (Ctrl-D).
Вхідний потік для командного інтерпретатора являє собою послідовність лексем. Основними синтаксичними елементами (лексемами) вважаються.
1. Коментарі. Коментар починається з символу # і продовжується до кінця рядка. Для того, щоб запобігти інтерпретації знака # як початку коментарю, необхідно помістити його в лапки, або поставити перед ним зворотну похилу риску "\".
2. Пропускові символи. Під пропусками розуміють символи "пропуск" (#20h), "tab", "повернення каретки". Пропуски використовуються для відокремлення окремих слів в рядку.
3. Відокремлювачі між висловлюваннями. До таких відокремлювачів відносяться крапка з комою (;) і повернення каретки. Кілька команд можуть бути введені з одного рядка, відокремлені крапками с комою - це еквівалентно вводу кожної команди з окремого рядка. Деякі команди вимагають кілька рядків вводу (if або while).
4. Оператори. Оператор – це спеціальний символ або послідовність символів, за якою оболонка закріплює окремий синтаксичний зміст. Знаки пунктуації, що мають значення для оболонки, повинні бути сховані від неї в лапках, щоб не привести до їх невірного тлумачення.
5. Слова. Словом будемо називати яку завгодно послідовність символів, заключених між пропусковими символами, відокремлювачами і операторами. Словом може бути група послідовних символів, рядок в лапках, посилання на змінну, маска файлу, заміщена команда та ін. Словом може бути комбінація всього вищезазначеного. Кінцеве значення слова - це результат виконання всіх підстановок і замін, який разом зі звичайними символами формує рядок. Цей рядок інтерпретується оболонкою як команда і список параметрів, що передаються.
6.1.5 Шаблони і підстановки
В кожному командному інтерпретаторі реалізовано механізм підстановки імен файлів. При цьому використовуються наступні конструкції:
* яка завгодно послідовність символів, включаючи порожню;
? який завгодно символ. Кілька знаків питання означають яку завгодно послідовність символів заданої довжини;
[] який завгодно символ з списку;
[^ ] все що завгодно, крім символів списку;
{} кожен елемент списку. При цьому не відбувається перевірка існування файлу (каталогу), а виконується безумовна підстановка, причому стільки разів, скільки елементів в списку;
~ домашній каталог.
Наприклад, нехай деякий каталог містить такі файли:
aaa, bbb, abc, cba, cccc
Наведемо приклади підстановки імен файлів в командний рядок:
Мета-послідовність Результат підстановки
* aaa abc bbb cba cccc
??a aaa cba
*[b,c] abc bbb cccc
[a-z]?a aaa cba
*[^b,c] aaa cba
{a,b,c}bb abb bbb cbb
(при цьому не перевіряється, чи існують ці файли в дійсності)
6.1.6 Спеціальні символи (метасимволи)
Багато знаків пунктуації інтерпретуються оболонкою як службові. До них відносяться:
~ ` ! @ # $ % ^ & * ( ) \ | { } [ ] ; ' " < > ?
Для того, щоб не дати інтерпретатору обробляти метасимволи по-своєму, необхідно перед ними ставити зворотну косу риску "\", або поміщати необхідну лексему в прямі одинарні або подвійні лапки. Зворотна коса риска "ховає" від оболонки значущу характеристику наступного символу і заставляє обробляти його як простий символ ASCII. Дія подвійних і одинарних лапок практично однакова, але подвійні лапки допускають дію деяких спеціальних символів. Наприклад:
$ touch a\ strange\ file
В результаті цієї команді в поточному каталозі буде створено файл, в імені якого будуть присутніми два пропуски - "a strange file".
Необхідно розрізняти метасимволи в шаблонах команд (що передаються як аргументи) і метасимволи підстановки імен файлів. Вводячи команду з термінала, не забувайте, що спочатку в неї "загляне" командний інтерпретатор, а лиш потім - програма. Тому потрібно стежити, щоб оболонка не перехопила спеціальні символи, їй не назначені, і не проводила підстановку імен файлів. Яскравим прикладом може служити програма grep - пошук в файлах по зразку.
Якщо з термінала ввести
$ grep [A-Z]* chap[12]
то інтерпретатор підставить в командний рядок всі імена файлів, що відповідають шаблону. В результаті підстановки може статися так:
$ grep Array.c Bug.c Comp.c README chap1 chap2
Таким чином, утиліта grep буде виконувати пошук рядка "Array.c" в файлах Bug.c, Comp.c, README, chap1, chap2. Для того щоб передати команді grep метасимволи, застосовуються лапки:
$ grep "[A-Z]*" chap[12]
При цьому буде виконуватися пошук послідовності з нуля і більш великих латинських букв в файлах chap1 chap2.