Лабораторна робота №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.