В цьому розділі ми обговоримо, як взаємодіяти^interactive з користувачами наших сценаріїв:
- друкування зрозумілих повідомлень та пояснень
- отримання вводу від користувача
- повідомлення користувача про необхідність вводу інформації
- використання дескрипторів файлів для зчитування та запису у багато файлів
Відображення наших повідомлень
Діалоговий чи ні?
Деякі сценарії запускаються та працюють без будь-якої взаємодії з користувачем. Перевагами таких сценаріїв є їх передбачуваність та можливість запуску у фоновому режимі. З іншого боку, багато сценаріїв вимагають вводу інформації від користувача, або ж, навпаки, виводять якусь інформацію. Вони надають можливості постановки більш гнучких завдань, зміни поведінки сценарію в залежності від певних умов та виводять інформацію про перебіг виконання завдання.
Під час написання інтерактивних сценаріїв не відмовляйтесь від звички писати коментарії. Сценарій, що друкує зрозумілі, слушні коментарії є значно зручнішим для користувача та може бути набагато легше налагоджений. Сценарій може чудово справлятись з роботою, але ви отримаєте масу несхвальних відгуків, якщо він не інформуватиме користувача про хід своєї роботи. Отож, включайте повідомлення, котрі б просили користувача дочекатись завершення обрахунків. Якщо можливо – старайтесь показати, скільки йому залишилось чекати, особливо якщо чекання зазвичай займає багато часу.
Коли повідомляєте користувача про необхідність вводу, краще надати забагато інформації про тип очікуваних даних, аніж не надати її взагалі. Це також передбачає перевірку введених даних та вивід відповідного повідомлення.
Bash має дві команди – echo та printf – для надання користувачам інформації, і щоб ви як мінімум вміли обходитись з однією з них, нижче ми продемонструємо кілька прикладів з командою echo.
Вживання вбудованої команди echo
Вбувала команда echo виводить свої аргументи, розділені пробілами та завершені символом нового рядка. Команда завжди повертає нуль; приймає декілька опцій:
- -e – інтерпретує символи, екрановані символом зворотної косої
- -n – не вставляє символ нового рядка в кінці виводу
Ось приклад додавання коментарів; ми спробували зробити сценарії feed.sh та penguin.sh з параграфу 7.2.1.2 трохи кращими^camel:
michel ~/test> cat penguin.sh
#!/bin/bash
# цей сценарій надає можливість нагодувати Тукса. Він буде радий
# лише рибі. Задля розваги ми додали ще кілька тварин.
if [ "$menu" == "fish" ]; then
if [ "$animal" == "penguin" ]; then
echo -e "Мммммммм… Риба. Тукс щасливий!\n"
elif [ "$animal" == "dolphin" ]; then
echo -e "\a\a\aПуііііітпііітріітуіііт!\a\a\a\n"
else
echo -e "*Пфррррртттт*\n"
fi
else
if [ "$animal" == "penguin" ]; then
echo -e "Тукс цього не хоче. Тукс хоче риби!\n"
exit 1
elif [ "$animal" == "dolphin" ]; then
echo -e "\a\a\a\a\a\aПуіііпуііішпііітдепуіііт!\a\a\a"
exit 2
else
echo -e "Ти це читав? Не дратуй "$animal"s!\n"
exit 3
fi
fi
michel ~/test> cat feed.sh
#!/bin/bash
# Цей сценарій працює з станом виходу penguin.sh
if [ "$#" != "2" ]; then
echo -e "Вживання:\t$0 страва стварина\n"
exit 1
else
export menu="$1"
export animal="$2"
echo -e "Пропоную $menu для $animal...\n"
feed="/nethome/anny/testdir/penguin.sh"
$feed $menu $animal
result="$?"
echo -e "Закінчив годівлю.\n"
case "$result" in
1)
echo -e "Вартовий: \"В б дали їм риби, поки вони не розсердились...\"\n"
;;
2)
echo -e " Вартовий: \"Не дивно, що вони тікають з нашої планети...\"\n"
;;
3)
echo -e " Вартовий: \"Купи їжу, що продається на вході, ти, ***\"\n"
echo -e " Вартовий: \"Ти що, хочеш їх отруїти?\"\n"
;;
*)
echo -e " Вартовий: \"Не забудь посібник!\"\n"
;;
esac
fi
echo "Завершую..."
echo -e "\a\a\Спасибі за відвідини зоопарку. Будемо раді бачити вас знову!\n"
michel ~/test> feed.sh яблуко верблюд
Пропоную яблуко для верблюд...
Ти це читав? Не зли верблюд
Закінчив годівлю.
Вартовий: "Купи їжу, що продається на вході, ти, ***"
Вартовий: "Ти що, хочеш їх отруїти?"
Завершую...
Спасибі за відвідини зоопарку. Будемо раді бачити вас знову!
michel ~/test> feed.sh яблуко
Вживання: ./feed.sh страва тварина
Додаткова інформація про символи екранування міститься в параграфі 3.3.2. Нижче подано список екранованих послідовностей, що їх розпізнає команда echo:
\a : Попередження (дзвоник)
\b : Повернення на одну позицію з витиранням
\c : Подавити кінцевий символ нового рядка
\e : Відмінити
\f : Зміна сторінки
\n : Новий рядок
\r : Повернення каретки
\t : Горизонтальний табулятор
\v : Вертикальний табулятор
\ : Зворотна похила риска
\ONNN : Восьми бітний символ, чиє значення у вісімковій системі числення становить NNN (від одного до трьох вісімкових чисел)
\NNN : Восьми бітний символ, чиє значення у вісімковій системі числення становить NNN (від одного до трьох вісімкових чисел)
\xHH : Восьми бітний символ, чиє значення у шістнадцятковій системі числення становить НН (від одного до двох шістнадцяткових чисел)
Для додаткової інформації про команду printf зверніться до сторінок довідки bash.
Отримання вводу від користувача
Вживання вбудованої команди read
Вбудована команда read є сусідом команд echo та printf. Синтаксис цієї команди наступний:
read [options] NAME1 NAME2 ... NAMEN
З стандартного вводу або з дескриптора файлу, заданого опцією –u, зчитується один рядок. Перше слово цього рядка присвоюється змінній NAME1, друге – наступній і так далі. Якщо слів є більше, аніж змінних, то всі слова, що залишились, присвоюються змінній NAMEN. Якщо слів є менше, аніж змінних, то змінним, що залишились присвоюються порожні значення.
Для поділу на слова чи лексеми використовується змінна IFS (див параграф 3.4.8). Символ зворотної косої може бути вжитий для екранування спеціального значення наступного символу, а отже і для символу нового рядка.
Якщо команді не задано жодної змінної, прочитаний рядок записується у змінну REPLY.
Станом виходу для команди read є нуль за винятком тих випадків, коли отримано символ кінця файлу, закінчився час очікування чи файловий дескриптор, переданий опцією -u виявився невірним.
Команда read розуміє наступні опції:
-a ANAME : всі слова послідовно присвоюються елементам масиву ANAME. Масив попередньо очищується. Інші аргументи NAME ігноруються.
-d DELIM : Перший символ слова DELIM вживається для позначення кінця рядка замість символу нового рядка.
-e : для зчитування рядка використовується функція readline.
-n NCHARS : read закінчує свою роботу після зчитування NCHARS символів, не дочікуючись символу кінця рядка.
-p PROMPT : Надрукувати текст PROMPT без символу нового рядка перед очікуванням вводу. Текст друкується лише якщо ввід йде з терміналу.
-r : Якщо задана ця опція, символ зворотної косої не працює як екрануючий.
-s : Простий режим. Якщо ввід йде з терміналу, символи не дублюються.
-t TIMEOUT : Заставляє read перервати роботу та завершитись з помилкою, якщо на протязі TIMEOUT секунд не було отримано повного рядка. Ця опція не дає ефекту, якщо зчитування не відбувається з терміналу чи абстрактного файлу.
-u FD : Зчитувати ввід з файлового дескриптора FD.
Даний приклад є виправленим варіантом сценарію leaptest.sh з попереднього розділу.
michel ~/test> cat leaptest.sh
#!/bin/bash
# This script will test if you have given a leap year or not.
echo "Type the year that you want to check (4 digits), followed by [ENTER]:"
read year
if (( ("$year" % 400) == "0" )) || (( ("$year" % 4 == "0") && ("$year" % 100 !=
"0") )); then
echo "$year is a leap year."
else
echo "This is not a leap year."
fi
michel ~/test> leaptest.sh
Type the year that you want to check (4 digits), followed by [ENTER]:
2000
2000 is a leap year.
Повідомлення користувача про необхідність вводу інформації
Наступний приклад продемонструє вам, як можна пояснювати користувачеві, що йому потрібно ввести.
michel ~/test> cat friends.sh
#!/bin/bash
# This is a program that keeps your address book up to date.
friends="/var/tmp/michel/friends"
echo "Hello, "$USER". This script will register you in Michel's friends database."
echo -n "Enter your name and press [ENTER]: "
read name
echo -n "Enter your gender and press [ENTER]: "
read -n 1 gender
echo
grep -i "$name" "$friends"
if [ $? == 0 ]; then
echo "You are already registered, quitting."
exit 1
elif [ "$gender" == "m" ]; then
echo "You are added to Michel's friends list."
exit 1
else
echo -n "How old are you? "
read age
if [ $age -lt 25 ]; then
echo -n "Which colour of hair do you have? "
read colour
echo "$name $age $colour" >> "$friends"
echo "You are added to Michel's friends list. Thank you so much!"
else
echo "You are added to Michel's friends list."
exit 1
fi
fi
michel ~/test> cp friends.sh /var/tmp; cd /var/tmp
michel ~/test> touch friends; chmod a+w friends
michel ~/test> friends.sh
Hello, michel. This script will register you in Michel's friends database.
Enter your name and press [ENTER]: michel
Enter your gender and press [ENTER] :m
You are added to Michel's friends list.
michel ~/test> cat friends
Зауважте, що вивід тут опущено. Сценарій лише зберігає інформацію про людей, що потрібні Майклові, але він також попереджує, якщо така людина вже є у списку. Інші можуть розпочати виконання сценарію:
[anny@octarine tmp]$ friends.sh
Hello, anny. This script will register you in Michel's friends database.
Enter your name and press [ENTER]: anny
Enter your gender and press [ENTER] :f
How old are you? 22
Which colour of hair do you have? black
You are added to Michel's friends list.
Через деякий час список friends набуде приблизно такого вигляду:
tille 24 black
anny 22 black
katya 22 blonde
maria 21 black
Звісно, ситуація далека від ідеалу, якщо кожен може редагувати (але не витирати) файли Майкла. Ви можете вирішити цю проблему, використовуючи спеціальні режими доступу до файлів сценаріїв; дивіться опис SUID та SGID у вступі до посібника користувача Linux.
Перенаправлення та дескриптори файлів
Загальне
Як ви вже, мабуть, знаєте, ввід та вивід команд може бути перенаправлений до їх виконання за допомогою спеціальних операторів перенаправлення, що інтерпретуються оболонкою. Перенаправлення також може вживатися для відкривання й закривання файлів у поточному середовищі виконання оболонки.
Перенаправлення може вживатись також і в сценаріях, отож вони можуть отримувати інформацію з файлів та записувати її туди. Пізніше користувач може переглянути створений файл, або ж він може використовуватись іншим сценаріям як джерело інформації.
Ввід та вивід файлів здійснюються цілочисельними індексами^integerhandles, що відслідковують всі відкриті файли для даного процесу. Ці числові значення відомі як дескриптори файлів. Ви мабуть чули про стандартні дескриптори stdin, stdout та stderr, що мають відповідно значення 0, 1 та 2. Ці числа та відповідні пристрої зарезервовані для внутрішнього вжитку. Bash може також приймати порти TCP чи UDP як файлові дескриптори.
Вивід внизу демонструє, як зарезервовані файлові дескриптори вказують на справжні пристрої:
michel ~> ls -l /dev/std*
lrwxrwxrwx 1 root root 17 Oct 2 07:46 /dev/stderr -> ../proc/self/fd/2
lrwxrwxrwx 1 root root 17 Oct 2 07:46 /dev/stdin -> ../proc/self/fd/0
lrwxrwxrwx 1 root root 17 Oct 2 07:46 /dev/stdout -> ../proc/self/fd/1
michel ~> ls -l /proc/self/fd/[0-2]
lrwx------ 1 michel michel 64 Jan 23 12:11 /proc/self/fd/0 -> /dev/pts/6
lrwx------ 1 michel michel 64 Jan 23 12:11 /proc/self/fd/1 -> /dev/pts/6
lrwx------ 1 michel michel 64 Jan 23 12:11 /proc/self/fd/2 -> /dev/pts/6
Ви можете переглянути nfo MAKEDEV та info proc для одержання детальнішої інформації про підкаталоги /proc, та про те, як ваша система керує стандартними дескрипторами файлів для кожного процесу.
Якщо ви запускаєте сценарій з командного рядка, то нічого особливого не відбувається, бо дочірній процес використовує ті ж самі файлові дескриптори, що й батьківський. Якщо ж батьківського процесу немає (наприклад, ваш сценарій запущено за допомогою ?cron), то стандартні файлові дескриптори є абстрактними чи іншими (тимчасовими) файлами до того часу, поки не зустрінеться якась форма перенаправлення. Це продемонстровано у нижченаведеному прикладі, який показує вивід простого сценарію at:
michel ~> date
Fri Jan 24 11:05:50 CET 2003
michel ~> at 1107
warning: commands will be executed using (in order)
a) $SHELL b) login shell c)/bin/sh
at> ls -l /proc/self/fd/ > /var/tmp/fdtest.at
at> <EOT>
job 10 at 2003-01-24 11:07
michel ~> cat /var/tmp/fdtest.at
total 0
lr-x------ 1 michel michel 64 Jan 24 11:07 0 -> /var/spool/at/!0000c010959eb (deleted)
l-wx------ 1 michel michel 64 Jan 24 11:07 1 -> /var/tmp/fdtest.at
l-wx------ 1 michel michel 64 Jan 24 11:07 2 -> /var/spool/at/spool/a0000c010959eb
lr-x------ 1 michel michel 64 Jan 24 11:07 3 -> /proc/21949/fd
І теж саме за допомогою cron:
michel ~> crontab -l
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.21968 installed on Fri Jan 24 11:30:41 2003)
# (Cron version -- $Id: chap8.xml,v 1.6 2005/03/01 19:39:20 tille Exp $)
32 11 * * * ls -l /proc/self/fd/ > /var/tmp/fdtest.cron
michel ~> cat /var/tmp/fdtest.cron
total 0
lr-x------ 1 michel michel 64 Jan 24 11:32 0 -> pipe:[124440]
l-wx------ 1 michel michel 64 Jan 24 11:32 1 -> /var/tmp/fdtest.cron
l-wx------ 1 michel michel 64 Jan 24 11:32 2 -> pipe:[124441]
lr-x------ 1 michel michel 64 Jan 24 11:32 3 -> /proc/21974/fd
Перенаправлення помилок
З попередніх прикладів зрозуміло, що ми можемо перепризначати файли вводу та виводу для сценаріїв, але дехто забуває перенаправляти помилки – вивід, що може виникнути пізніше. Отож, якщо ви везунчик, помилки будуть відправлені вам поштою разом з коментаріями про можливі причини. Якщо ж ні – помилки призведуть до аварійної зупинки сценарію, вам не буде відправлено звіту і ви не зможете зробити якісної наладки. Під час перенаправлення пам’ятайте, що порядок слідування операторів має значення. До прикладу, наведена команда, запущена у /var/spool
ls -l * 2 > /var/tmp/unaccessible-in-spool
перенаправить вивід команди ls до файлу unaccessible-in-spool у /var/tmp/. Команда
ls -l * > /var/tmp/spoollist 2 >& 1
перенаправить стандартний вивід та стандартні повідомлення про помилки у файл spoollist. А команда
ls -l * 2 >& 1 > /var/tmp/spoollist
перенаправить лише стандартний вивід до файлу призначення, тому що стандартні помилки копіюються у стандартний вивід до перенаправлення стандартного виводу. Доволі часто помилки перенаправляються у /dev/null, якщо є впевненість, що інформація про них непотрібна. Сотні прикладів цього ви зможете знайти у стартових сценаріях вашої системи. Bash дозволяє перенаправити одночасно стандартний вивід та стандартні помилки в результат розширення виразу FILE наступної конструкції:
&> FILE
Це є еквівалентом
> FILE 2>&1
конструкції, що вживалась у попередніх прикладах. Доволі часто цей вираз також вказує на /dev/null, наприклад, якщо ви хочете лише виконати команду, без різниці, що вона там виводить та які помилки видає.
Ввід та вивід файлу
Вживання /dev/fd
Каталог /dev/fd містить елементи, названі 0, 1, 2 і т.д. Відкривання файлу /dev/fd/N еквівалентне дублюванню файлового дескриптора N. Якщо ваша система підтримує /dev/stdin, /dev/stdout та /dev/stderr, ви побачите, що вони еквівалентні відповідно /dev/fd/0, /dev/fd/1 та /dev/fd/2.
В основному файли /dev/fd/ використовуються з оболонки. Цей механізм дозволяє програмам, які використовують імена файлів, обробляти стандартний ввід, вивід та помилки так само, як і інші файли. Якщо /dev/fd недоступний у вашій системі, ви знайдете спосіб обійти цю проблему. Це може бути зроблено, наприклад, вживанням дефісу (-), який показує, що програма отримує ввід з абстрактного файлу:
michel ~> filter body.txt.gz | cat header.txt - footer.txt
This text is printed at the beginning of each print job and thanks the sysadmin
for setting us up such a great printing infrastructure.
Text to be filtered.
This text is printed at the end of each print job.
Команда cat спершу зчитує файл header.txt, далі її стандартний ввід, який є виводом команди filter та наприкінці – файл footer.txt. Особливе значення дефіса як аргументу командного рядка для посилання на стандартний ввід чи вивід є доволі поширеним непорозумінням. Також можуть виникнути помилки при вживання дефіса першим аргументом, оскільки він може бути інтерпретований як опція для попередньої команди. Вживання /dev/fd сприяє стандартизації та допомагає уникнути помилок:
michel ~> filter body.txt | cat header.txt /dev/fd/0 footer.txt | lp
У цьому, покращеному прикладі весь вивід додатково по конвеєру направляється на стандартний принтер за допомогою команди lp.
Зчитування та виконання
Присвоювання файлових дескрипторів файлам
Іншим підходом до роботи з файловими дескрипторами є сприймання їх як спосіб присвоїти цифровий ідентифікатор файлові. Замість вживання імені файлу ви можете використовувати номер файлового дескриптора. Вбудована команда exec вживається для присвоювання файлового дескриптора файлові. Використання:
exec fdN> file
для присвоєння файлового дескриптора N для виводу файлу, та
exec fdN< file
для присвоєння файлового дескриптора N для вводу файлу. Після того, як файлові був призначений дескриптор, останній може вживатись у операціях перенаправлення, як це показано у наступному прикладі:
michel ~> exec 4 > result.txt
michel ~> filter body.txt | cat header.txt /dev/fd/0 footer.txt >& 4
michel ~> cat result.txt
This text is printed at the beginning of each print job and thanks the sysadmin
for setting us up such a great printing infrastructure.
Text to be filtered.
This text is printed at the end of each print job.
Примітка: Файловий дескриптор 5
Вживання цього дескриптора може призвести до проблем, зверніться до Посібника для розширеного програмування на Bash, розділ 16; вам наполегливо рекомендується не вживати його.
Зчитування у сценаріях
Наступний приклад демонструє, як ви можете вибирати між вводом з консолі та вводом з файлу:
michel ~/testdir> cat sysnotes.sh
#!/bin/bash
# This script makes an index of important config files, puts them together in
# a backup file and allows for adding comment for each file.
CONFIG=/var/tmp/sysconfig.out
rm "$CONFIG" 2>/dev/null
echo "Output will be saved in $CONFIG."
exec 7<&0
exec < /etc/passwd
# Read the first line of /etc/passwd
read rootpasswd
echo "Saving root account info..."
echo "Your root account info:" >> "$CONFIG"
echo $rootpasswd >> "$CONFIG"
exec 0<&7 7<&-
echo -n "Enter comment or [ENTER] for no comment: "
read comment; echo $comment >> "$CONFIG"
echo "Saving hosts information..."
# first prepare a hosts file not containing any comments
TEMP="/var/tmp/hosts.tmp"
cat /etc/hosts | grep -v "^#" > "$TEMP"
exec 7<&0
exec < "$TEMP"
read ip1 name1 alias1
read ip2 name2 alias2
echo "Your local host configuration:" >> "$CONFIG"
echo "$ip1 $name1 $alias1" >> "$CONFIG"
echo "$ip2 $name2 $alias2" >> "$CONFIG"
exec 0<&7 7<&-
echo -n "Enter comment or [ENTER] for no comment: "
read comment; echo $comment >> "$CONFIG"
rm "$TEMP"
michel ~/testdir> sysnotes.sh
Output will be saved in /var/tmp/sysconfig.out.
Saving root account info...
Enter comment or [ENTER] for no comment: hint for password: blue lagoon
Saving hosts information...
Enter comment or [ENTER] for no comment: in central DNS
michel ~/testdir> cat /var/tmp/sysconfig.out
Your root account info:
root:x:0:0:root:/root:/bin/bash
hint for password: blue lagoon
Your local host configuration:
127.0.0.1 localhost.localdomain localhost
192.168.42.1 tintagel.kingarthur.com tintagel
in central DNS
Закривання файлових дескрипторів
Оскільки дочірні процеси успадковують відкриті файлові дескриптори, хорошою практикою є закривати їх, коли вони більше не потрібні. Це робиться таким чином:
exec fd<&
В прикладі, що наводився вище, файловий дескриптор 7, що був призначений стандартному вводу, закривається щоразу, коли користувачеві потрібно отримати доступ до справжнього стандартного вводу (як правило – клавіатури). Нижче наведено простий приклад перенаправлення в абстрактний файл лише повідомлень про помилки:
michel ~> cat listdirs.sh
#!/bin/bash
# This script prints standard output unchanged, while standard error is
# redirected for processing by awk.
INPUTDIR="$1"
exec 6>&1
ls "$INPUTDIR"/* 2>&1 >&6 6>&- \
# Closes fd 6 for awk, but not for ls.
| awk 'BEGIN { FS=":" } { print "YOU HAVE NO ACCESS TO" $2 }' 6>&-
exec 6>&-
Документні вставки^heredocument
Доволі часто ваш сценарій повинен викликати іншу програму чи сценарій, що потребують вводу інформації від користувача. Документні вставки забезпечують спосіб вказівок оболонці зчитувати ввід з поточного джерела поки не зустрінеться рядок, що містить лише вказаний ланцюжок^linestring (без кінцевих пробілів). Всі інші рядки без змін передаються викликаній команді. Як результат – вам не потрібно запускати інші команди; ви можете вживати лише визначені символи і це виглядатиме значно краще, аніж купа echo-ів:
michel ~> cat startsurf.sh
#!/bin/bash
# This script provides an easy way for users to choose between browsers.
echo "These are the web browsers on this system:"
# Start here document
cat << BROWSERS
mozilla
links
lynx
konqueror
opera
netscape
BROWSERS
# End here document
echo -n "Which is your favorite? "
read browser
echo "Starting $browser, please wait..."
$browser &
michel ~> startsurf.sh
These are the web browsers on this system:
mozilla
links
lynx
konqueror
opera
netscape
Which is your favorite? opera
Starting opera, please wait...
Хоча ми ведемо мову про документну вставку, вона може бути конструкцією в тому ж самому сценарієві. Ось приклад, який автоматично встановлює пакунок, так ніби ви підтверджуєте всі запитання:
#!/bin/bash
# This script installs packages automatically, using yum.
if [ $# -lt 1 ]; then
echo "Usage: $0 package."
exit 1
fi
yum install $1 << CONFIRM
y
CONFIRM
А ось приклад його вживання. На запитання "Is this ok [y/N]" сценарій відповідає “y”:
[root@picon bin]# ./install.sh tuxracer
Gathering header information file(s) from server(s)
Server: Fedora Linux 2 - i386 - core
Server: Fedora Linux 2 - i386 - freshrpms
Server: JPackage 1.5 for Fedora Core 2
Server: JPackage 1.5, generic
Server: Fedora Linux 2 - i386 - updates
Finding updated packages
Downloading needed headers
Resolving dependencies
Dependencies resolved
I will do the following:
[install: tuxracer 0.61-26.i386]
Is this ok [y/N]: EnterDownloading Packages
Running test transaction:
Test transaction complete, Success!
tuxracer 100 % done 1/1
Installed: tuxracer 0.61-26.i386
Transaction(s) Complete
Підсумок
В цьому розділі повідомляти користувача про необхідність вводу інформації та інформувати його про хід виконання роботи. Ми також обговорили ввід та вивід файлів з допомогою файлових дескрипторів та перенаправлення, та як це може вживатись для отримання інформації від користувача.
Ми підкреслили важливість забезпечення достатньою інформацією користувачів наших сценаріїв. Як завжди при вживанні сценаріїв – краще забагато інформації, аніж замало.
Документні вставки – це тип конструкцій оболонки, що дозволяє створювати списки, пропонуючи вибір користувачеві. Ця конструкція також може вживатись для виконання інших інтерактивних завдань у фоновому режимі без переключення.
Вправи
Наведені вправи є практичним додатком до конструкцій, що обговорювались в даному розділі. Під час написання сценаріїв їх варто тестувати у спеціально створеному каталозі, що не містить великої кількості даних. Реалізуйте один крок, а далі протестуйте його; це буде значно ефективніше, аніж писати все одразу, а потім все одразу наладжувати.
- Напишіть сценарій, котрий би запитував вік користувача.
Якщо вік більший чи рівний 16, видруковував повідомлення, що користувачеві можна вживати алкоголь.
Якщо вік менший аніж 16, друкувати повідомлення, де вказувати, через скільки років йому чи їй можна буде вживати алкоголь.
На додачу порахуйте скільки пива випив користувач, котрому більше 18 років, якщо в середньому за рік він випиває 100 літрів пива. - Напишіть сценарій, що приймає як аргумент один файл. За допомогою документної вставки дайте можливість користувачеві вибрати метод стиснення файлу серед таких: gzip, bzip2, compress і zip.
- Напишіть сценарій під назвою homebackup, що автоматизує tar для кінцевого користувача,
котрий завжди вводить опції cvp та робить резервні копії домашнього каталогу у /var/backups.
Сценарій повинен вміти:
- перевіряти кількість аргументів. Сценарій повинен запускатись без аргументів; у такому випадку він має надрукувати інформативне повідомлення.
- визначати, чи має цільовий каталог достатньо місця щоб вмістити резервну копію.
- запитувати користувача, повну чи покрокову копію даних він хоче зробити. Якщо користувач ще не має повної копії даних, надрукувати повідомлення, що така копія буде зроблена. У випадку покрокового копіювання даних робити його лише якщо повна копія не більш аніж тижневої давності.
- стиснути резервну копію за допомогою будь-якого інструменту для стиснення даних. Попередити користувача про це, бо стиснення даних може зайняти певний час на протязі якого користувач буде хвилюватись про відсутність даних на екрані.
- надрукувати повідомлення, що інформує користувача про розмір отриманого стиснутого файлу.
Перегляньте info tar, або Вступ до Linux, розділ 9: «Підготовка ваших даних» для додаткової інформації.
- Напишіть сценарій під назвою simple_useradd.sh, що додає нового користувача у систему. Сценарій повинен:
- приймати лише один аргумент, в іншому випадку завершувати роботу після виведення інформативного повідомлення
- перевіряти /etc/passwd та вирішувати, який ідентифікатор присвоювати користувачеві. Друкувати повідомлення, що містить цей ідентифікатор.
- створювати особисту групу для цього користувача, перевіривши файл /etc/group. Надрукувати повідомлення, що містить ідентифікатор групи.
- зібрати у оператора інформацію про користувача: коментар, що описує нового користувача, вибір із списку оболонок (перевіряти на наявність та сумісність; виходити при невдачі, надрукувавши відповідне повідомлення), дата завершення дії облікового запису користувача (user account), список додаткових груп, у котрі може входити користувач.
- на основі отриманої інформації додайте відповідні записи у файли /etc/passwd, /etc/group, /etc/shadow; створіть домашній каталог користувача (з правильними правами доступу!); додайте користувача до відповідних груп.
- задайте користувачеві ваш стандартний пароль
Перепишіть сценарій з параграфу 7.2.1.4 так, щоб він отримував інформацію від користувача, а не з першого агументу.
Українськими відповідниками слова interactive є «діалоговий», «взаємодіючий» тому під час перекладу я вживатиму всі терміни рівноправно; термін «інтерактивний» я вжив у заголовку тому, що він НМД більш звичний.
Добре, що в англійській слова не змінюються у відмінках. Схожий сценарій українською буде значно складніший, а перекладати таки варто… Чи не варто в цьому випадку?..