Писане на скриптове за bash шел : версия 2



Дата06.02.2017
Размер281.23 Kb.
#14338
Писане на скриптове за BASH

шел : версия 1.2

Статията е взета от http://linux-bg.exco.net/

Тази статия е преведена с разрешението на автора и X_console.
Адресът на оригиналната статия е http://xfactor.itec.yorku.ca/~xconsole/.

Както всички шелове, който може да намерите за Linux BASH (Bourne Again SHell) е не само отличен команден интерпретатор но и език за писане на криптове. Шел(Shell) скриптовете ви позволяват максимално да използвате възможностите на шел интерпретатора и да автоматизирате множество задачи. Много от програмите, който може да намерите за Linux в последно време са шел скриптове. Ако искате да разберете как те работят или как може да ги редактирате е важно да рабирате синтаксиса и семантиката на BASH шела. В допълнение познаването на bash езика ви позволява да напишете ваши собствени програми, който да изпълняват точно това което искате.



Програмиране или писане на скрипове?
Хората който до сега не са се занимавали с програмиране обикновено не разбират разликата между програмен и скрипт език. Програмните езици обикновено са по-мощни и по-бързи от скрипт езиците. Примери за програмни езици са C, C++, и Java. Програмите който се пишат на тези езици обикновено започват от изходен код (source code) - текст който съдържа инструкции за това как окончателната програма трябва да работи след което се компилират до изпълним файл. Тези изпълними файлове не могат лесно да бъдат адаптирани за различни операционни системи (ОС). Например ако сте написали програма на C за Linux изпълнимият файл няма да тръгне под Windows 98. За да можете да я използвате тази програма се налага да прекомпилирате изходния код под Windows 98. Скриптовете (програмите писани на скрипт езици) също започват от изходен, но не се компилират в изпълними файлове. При тях се изполва интерпретатор който чете инструкциите от изходния код и ги изпълнява. За жалост, поради това че интерпретатора трябва да прочете всяка команда преди да я изпълни, интерпретираните програми вървят като цяло по-бавно спрямо компилираните. Основното предимство на скриптовете се е, че лесно могат да бъдат пренаписани за други ОС стига да има интерпретатор за тази ОС. bash е скрипт език. Той е идеален за малки програми. Други скрип езици са Perl, Lisp, и Tcl.

Какво искате да знаете?

Писането на собствени шел скриптове изисква от вас да знаете най-основните команди на Linux. Трябва да знаете например как да копирате, местите или създавате нови файлове. Едно от нещата което е задължително да знаете е как да работите с текстов редактор. За Linux има множество текстови редактори най-разпространените от който са vi, emacs, pico, mcedit.



Внимание!!!
Не се упражнявайте в писане на скриптове като root потребител! Не се знае какво може да се случи! Аз няма да бъда отговорен ако вие по невнимание повредите вяшата система. Имайте това в предвид! За упражненията изполвайте нормален потребител без права на root.

Вашият първи BASH скрипт
Първият скрипт който ще напишете е класическата "Hello World" програма. Тази програма изпечатва единствено думите "Hello World" на екрана. Отворете любимия си текстов редактор и напишете:

#!/bin/bash


echo "Hello World"

Първият ред от програмата казва че ще използваме bash интерпретатора за да подкараме програмата. В този случай bash се намира в /bin директорията. Ако bash се намира в друга директория на вашата система тогава направете необходимите премени в първия ред. Изричното споменаване на това кой интерпретататор ще изпълнява скрипта е много важно, тъи като той казва на Linux какви инструкции могат да бъдат използвани в скрипта. Следващото нещо което трябва да направите е да запишете файла под името hello.sh. Остава само да направите файла изпълним. За целта пишете:

xconsole$ chmod 700 ./hello.sh

Прочетете упътването за използване на chmod командата ако не знаете как да променяте правата на даден файл. След като сте направили програмата изпълнима я стартирайте като напишете:

xconsole$ ./hello.sh

Резултатът от която ще бъде следният надпис на екрана

Hello World

Това е! Запомнете последователноста от действия - писане на кода, записване на файла с кода, и променянето на файла в изпълним с командата chmod.



Команди, Команди, Команди
Какво точно направи вашата първа програма? Тя изпечата думите "Hello World" на екрана. Но как програмата го направи това? С помоща на команди. Единственият ред с команди беше echo "Hello World". И коя е командата? echo.  Командата echo изпечатва всичко на екрана,  което е получила като свой аргумент.

Аргумент е всичко което е написано след името на командата. В нашият случай това е "Hello World". Когато напишете  ls /home/root,   командата е ls а нейният аргимент е /home/root. Какво означава всичко това? Това означава че ако имате програма или команда, която изпечатва аргументите си на екрана то може да я използвате вместо echo. Нека да предположим че имаме такава команда която се казва foo. Тази комада ще изпечата своите аргументи на екрана. Тогава нашият скрипт може да изглежда така:

#!/bin/bash
foo "Hello World"

Запишете го и го направете изпълним с chmod след което го стартирайте:

xconsole$ ./hello
Hello World

Точно същият резултат. Всичко което правихте до сега е да използвате echo командата във вашия шел скрипт. Друга команда за изпечатване е printf. Командата printf позволява повече контрол при изпечатване на информацията, особено ако сте запознати с програмния език C. Фактически съшият резултат от нашият скрипт можем да постигнем просто ако напишем в командния ред:

xconsole$ echo "Hello World"
Hello World

Както виждате може да използвате  Linux команди при писането на шел скриптове. Вашият bash шел скрипт е колекция от различни програми, специално написани заедно за да изпълнят конкретна задача.



Малко по-лесни програми
Сега ще напишем програма с която да преместим всички файлове от дадена директория в нова директория, след което ще изтрием новата директория заедно със нейното съдържание и ще я създадем отново. Това може да бъде направено със следната последователност от команди:

xconsole$ mkdir trash


xconsole$ mv * trash
xconsole$ rm -rf trash
xconsole$ mkdir trash

Вместо да пишем последователно тези команди можем да ги запишем във файл:

#!/bin/bash
mkdir trash
mv * trash
rm -rf trash
mkdir trash
echo "Deleted all files!"

Запишете файла под името clean.sh. След като стартирате clean.sh  той ще премести   всички файлове в директория trash, след което ще изтрие директорията заедно със съдържанието и ще я създаде отново. Дори ще изпечата съобщение на екрана, когато свърши със тези действия. Този пример показва и как да автоматизирате многократното писане на последователности от команди.



Коментари във скрипта
Коментарите ви помагат да направите вашата програма по-лесна за разбиране. Те не променят нищо в изпълнението на самата програма . Те се използват единствено за да може вие да ги четете. Всички коментари в bash започват със символа: "#", с изключение на първия ред (#!/bin/bash). Първият ред не е команда. Всички редове след първия който започват със "#" са коментари. Вижте кода на следния скрипт:

#!/bin/bash


# tazi programa broi chislata ot 1 do 10:
for i in 1 2 3 4 5 6 7 8 9 10; do
    echo $i
done

Дори и да не знаете bash, вие веднага може да се ориентирате какво прави скрипта, след като прочетете коментара. Добре е при писане на скриптове да използвате коментари. Ще откриете, че ако ви се наложи да промените накоя програма която сте писали преди време, коментарите ще ви бъдат от голяма полза.



Променливи
Променливите, най-общо казано, са  "кутии" който съхраняват информация. Вие може да използвате променливи за много неща. Те ви помагат да съхранявате информацията която е въвел потребителя, аргументи или числова информация. Погледнете този код:

#!/bin/bash


x=12
echo "Stoinosta na promenliwata x e $x"

Всичко което се случва е да присвоим на променливата x стойност 12 и да я отпечатаме тази стойност с комадата echo. echo "Stoinosta na promenliwata x e $x" изпечатва текущата стойност на x. Когато давате стойност на дадена променлива не трябва да има шпации между нея и "=". Ето какъв е синтаксиса:



име_на_променлива=стойност

Стойноста на променливата можем да получим като поставим символа "$" пред нея.   В конкретния случай за да изпечатаме стойноста на& x   пишем echo $x.

Има два типа променливи - локални променливи и променливи на обкръжението(environment). Променливите на обкръжението се задават от системата и информация за тях може да се получи като се използва env командата. Например:

xconsole$ echo $SHELL

Ще отпечата

/bin/bash

Което е името на шела който използваме в момента.  Променливите на обкръжението са дефинирани в  /etc/profile и  ~/.bash_profile. С echo командата можете лесно да проверите текущата стойност на дадена променлива, биля тя от обкръжението или локална. Ако все още се чудите защо са ни нужни променливи следната програма е добър пример който илюстрира тяхното използване:

#!/bin/bash


echo "Stojnosta na x e 12."
echo "Az imam 12 moliwa."
echo "Toj mi kaza che stojnosta na x e 12."
echo "Az sym na 12 godini."
echo "Kak taka stojnosta na x e 12?"

Да предположим че в един момент решите да промените стойноста на x от 12 на 8. Какво трябва да направите?  Трябва да премените навсяскъде в кода 12 с 8. Да но... има редове в който 12 не е стойноста на x. Трябва ли да променяме и тези редове? Не защото те не са свързани с x. Не е ли объркващо? По надолу е същия пример само че се използват променливи:

#!/bin/bash
x=12     # stoinosta na promenliwata x e 12 e x
echo "Stoinosta na  x e $x."
echo "Az imam 12 moliwa."
echo "Toj mi kaza che stojnosta na x e $x."
echo "Az sym na 12 godini."
echo "Kak taka stojnosta na x e $x?"

В този пример $x ще изпечата текущата стойност на x, която е 12. По този начин ако искате да промените стойноста на x  от 12 на  8 е необходимо единствено да замените реда в който пише x=12 с x=8. Другите редовете няма да бъдат променени. Променливити имат и дуги полезни свойства както ще се убедите сами в последствие.



Условни оператори
Условните оператори ви позволяват вашата програма да "взема решения" и я правят по-компактна. Което е по-важно с тях може да проверявате за грешки. Всички примери до сега започваха изпълнението си от първия ред до последния без никакви проверки. За пример:

#!/bin/bash


cp /etc/foo .
echo "Done."

Тази малка шел програма  копира файлът /etc/foo в текущата директория и изпечатва "Done" на екрана. Тази програма ще работи само при едно условие. Трябва да има файл /etc/foo. В противен случай ще се получи следния резултат:

xconsole$ ./bar.sh
cp: /etc/foo: No such file or directory
Done.

Както виждате имаме проблем. Не всеки който стартира вашата програма има файл /etc/foo на системата си. Ще бъде по-добре, ако вашата програма проверява дали файла /etc/foo съществува и ако това е така да продължи с копирането, в противен случай да спре изпълнението. С "псевдо" код това изглежда така:

if /etc/code exists, then
    copy /etc/code to the current directory
    print "Done." to the screen.
otherwise,
    print "This file does not exist." to the screen
    exit

Може ли това да бъде направено с bash? Разбира се! В bash условните оператори са: if, while, until, for, и case.   Всеки оператор започва с ключова дума и завършва с ключова дума. Например if оператора започва с ключовата дума if, и завършва с  fi. Условните оператори не са програми във вашата система. Те са вградени свойства на  bash.



if ... else ... elif ... fi
Е един от най-често използваните условни оператори. Той дава възможност на програма да вземе решения от рода на "направи това ако(if) това условие е изпълнено, или(else)   прави нещо друго". За да използвате ефективно условния оператор if трябва да използвате командата test. test проверява за съществуване на файл, права, подобия или разлики. Ето програмата bar.sh:

#!/bin/bash


if test -f /etc/foo
then
    # file exists, so copy and print a message.
    cp /etc/foo .
    echo "Done."
else
    # file does NOT exist, so we print a message and exit.
    echo "This file does not exist."
    exit
fi

Забележете че редовете след  then и else са малко по-навътре. Това не е задължително, но се прави с цел програмата да бъде по-лесна за четене. Сега стартирайте програмата. Ако имате файл /etc/foo, тогава програмата ще го копира в текущата директория, в противен случай ще върне съобщение за грешка. Опцията  -f проверява дали това е обикновен файл. Ето списък с опциите на  командата test:

-d проверява дали файлът е директория
-e проверява дали файлът съществува
-f проверява дали файлът е обикновен файл
-g проверява дали файлът има SGID права
-r проверява дали файлът може да се чете
-s проверява дали файлът разнерът на файла не е 0
-u проверява дали файлът има SUID права
-w проверява дали върху файлът може да се пише
-x проверява дали файлът е изпълним

else се използва ако искате вашата програма да направи нещо друго, ако първото условие не е изпълнено. Има и ключова дума elif, която може да бъде използвана вместо да пишете друг if вътре в първия if.  elif идва от английското "else if". Използва се когато първото условие не е изпълнено и искате да проверите за друго условие.

Ако не се чувствате комфортно с  if и test синтаксиса, който е :

if test -f /etc/foo


then

тогава може да използвате следния вариант:

if [ -f /etc/foo ]; then

Квадратните скоби формират  test командата. Ако имате опит в програмирането на C този синтакс може да ви се стори по-удобен. Забележете, че трябва да има разстояние след отварящата квадратна скоба и преди затварящата. Точката и запетаята: ";" казва на шела че това е края на командата. Всичко след ";" ще бъде изпълнено сякаш се намира на следващия ред. Това прави програмата малко по-четима. Можете разбира се да сложите  then на следващия ред.

Когато използваме променливи с  test е добре да ги заградим с кавички. Например:

if [ "$name" -eq 5 ]; then



while ... do ... done
while оператора е условен оператор за цикъл. Най-общо казано, това което прави е  "while(докато) това условие е вярно, do(изпълни) командите done ". Нека да видим следния пример:

#!/bin/bash


while true; do
   echo "Press CTRL-C to quit."
done

true в действителност е програма. Това което прави тази програма е да се изпълнява безкрайно. Използването на  true се смята, че забавя вашата програма, защото шел интерпретатора първо трябва да извика програмата и след това да я изпълни. Вместо това може да използвате командата ":":

#!/bin/bash
while :; do
   echo "Press CTRL-C to quit."
done

По този начин вие постигате същия резултат, но доста по бързо. Единствения недостатък е, че програмата става по-трудно четима.  Ето един по-подробен пример, който използва променливи:

#!/bin/bash
x=0;     # initialize x to 0
while [ "$x" -le 10 ]; do
    echo "Current value of x: $x"
    # increment the value of x:
    x=$(expr $x + 1)
    sleep 1
done

Както виждате използваме  test (записана като квадратни скоби) за да проверим състоянието на променливата  x. Опцията  -le проверява дали  x е по-малко(less) или равно(equal) на 10. На говорим език това се превежда по следния начин "Докато(while) x е по-малко или равно на 10, покажи текущата стойност на x, и след това добави 1 към текущата стойност на x.". sleep 1  казва на програмата да спре изпълнението си за една секунда. Както виждате това което правим тук в да проверим за равенство. Ето списък с някой опции на test:



Проверка за равенства между променливите x и y, ако променливите са  числа:
x -eq y   Проверява дали  x е равно на  y
x -ne y   Проверява дали  x не е равно на y
x -gt y   Проверява дали x е по-голямо от y
x -lt y   Проверява дали x е по-малко от y

Проверка за равенства между променливите x и y, ако променливите са  текст:
x = y   Проверява дали  x е същитата като  y
x != y   Проверява дали  x не е същитата като  y
-n x   Проверява дали x не е празен текст
-z x   Проверява дали x  е празен текст

От горния пример единственият ред, който може да ви се стори по-труден за рабиране е следния:

x=$(expr $x + 1)

Това което прави този ред е да увеличи стойноста на  x с 1. Но какво значи $(...)? Дали е променлива? Не. На практика това е начин да кажете на  шел интерпретатора, че ще изпълнявате командата expr $x + 1, и резултата от тази команда ще бъде присвоен на x. Всяка команда която бъде записана в  $(...) ще бъде изпълнена:

#!/bin/bash
me=$(whoami)
echo "I am $me."

Опитайте с този пример за да разберете какво имам предвид. Горната програмка може да бъде написана по-следния начин:

#!/bin/bash
echo "I am $(whoami)."

Сами си решете кой от начините е по-лесен за вас. Има и друг начин да изпълните команда или да присвоите разултата от изпълнението на дадена команда на променлива. Този начин ще бъде обяснен по-нататък. За сега използвайте $(...).



until ... do ... done
Условния оператор until е много близък до while. Единствената разлика е, че се обръща смисъла на условието и се взима предвид новото значение. Действието на until оператора е "докато(until) това условие е вярно, изпълнявай(do) командите". Ето пример:

#!/bin/bash


x=0
until [ "$x" -ge 10 ]; do
    echo "Current value of x: $x"
    x=$(expr $x + 1)
    sleep 1
done

Този код може би ви изглежда познат. Проверете го и вижте какво прави.  until ще изпълнява командите докато стойноста на променливата x е по-голяма или равна на 10. Когато стойноста на x стане 10 цикълът ще спре. Ето защо последната стойност на x която ще се изпечата е  9.



for ... in ... do ... done
for се използва кога искате да присвойте на дадена променлива набор от стойности. Например можете да напишете програма, която да изпечатва 10 точки всяка секунда:

#!/bin/bash


echo -n "Checking system for errors"
for dots in 1 2 3 4 5 6 7 8 9 10; do
    echo -n "."
done
echo "System clean."

В случай, че не знаете опцията  -n на командата echo спира автоматичното добавяне на нов ред. Пробвайте командата веднъж с   -n опцията и веднъж без нея за да разберете за какво става дума. Променливата dots преминава през стойностите от 1 до 10.  Вижте следния пример:

#!/bin/bash
for x in paper pencil pen; do
    echo "The value of variable x is: $x"
    sleep 1
done

Когато стартирате програмата ще видите че x в началото ще има стойност paper, след което ще премине на следващата стойност, която е pencil, и след това pen. Когато свършат стойностите през който минава цикъла изпълненито му завършва.

Ето една доста полезна програма. Тя добавя .html разширение на всички файлове в текущата директория:

#!/bin/bash


for file in *; do
    echo "Adding .html extension to $file..."
    mv $file $file.html
    sleep 1
done

Ако не знаете "*" е "wild card character". Това ще рече "всичко в текущата директория", което в нашия случай представлява всички файлове в тази директория. Променливата file ще премине през всички стойности, в този случай файловете в текущата директория. След което командата mv преименува стойностите на променливата file във такива с  .html разширение.



case ... in ... esac
Условния оператор case е близък до  if . За предпочитане е да се използва когато имаме голям брой условия който трябва да бъдат проверени. Вземете за пример следния код:

#!/bin/bash


x=5     # initialize x to 5
# now check the value of x:
case $x in
   0) echo "Value of x is 0."
      ;;
   5) echo "Value of x is 5."
      ;;
   9) echo "Value of x is 9."
      ;;
   *) echo "Unrecognized value."
esac

Оператора case ще провери стойност на  x на коя от  3-те възможности отговаря. В този случай първо ще провери дали стойноста на x е 0, след което ще провери за 5 и 9. Накая ако никое от условия не е изпълнено ще се изпечата съобшението "Unrecognized value.". Имайте предвид, че "*" означава "всичко", и в този случай това означава "която и да е стойност различна от посочените". Ако стойноста на  x е различна от 0, 5, или 9, то тогава тя попада в случая "*". Когато използвате  case всяко условие трябва да завършва с две ";". Може би се чудите защо да използвате  case когато може да използвате if? Ето как изглежда еквивалентната програма написана с  if. Вижте коя програма е по-бърза и по лесна за четене:

#!/bin/bash
x=5     # initialize x to 5
if [ "$x" -eq 0 ]; then
    echo "Value of x is 0."
elif [ "$x" -eq 5 ]; then
    echo "Value of x is 5."
elif [ "$x" -eq 9 ]; then
    echo "Value of x is 9."
else
    echo "Unrecognized value."

fi

Кавички


Кавичите играят голяма роля в шел програмирането. Има три различни вида. Те се двойни кавички: ", единична кавичка: ', и обратно наклонена кавичка: `. Различават ли се те една от друга? Да.

Обикновено използваме двойната кавичка за да обозначим с нея низ от символи и да запазим шпацията. Например, "Този низ съдържа шпации.". Низ заграден от двойни кавички се третира като един аргумент. Вземете следният скрипт за пример:

xconsole$ mkdir hello world
xconsole$ ls -F
hello/     world/

Създадохме две директории. Командата mkdir взе думите hello и world като два аргумента, създавайки по този начин две директории. А какво ще се случи сега:

xconsole$ mkdir "hello world"
xconsole$ ls -F
hello/     hello world/     world/

Създадохме една директория състояща се от две думи. Двойните кавички направиха командата да третира  двете думи като един аргумент . Без тях  mkdir щеше да приеме hello за първи аргумент и world за втори.

Единична кавичка се използва обикновено когато се занимаваме с променливи. Ако една променлива е заградена от двойни кавички, то нейната стойност ще бъде оценена. Но това няма да се случи ако използваме единични кавички. За да ви стане по-ясно разгледайте следният пример:

#!/bin/bash


x=5     # stojnosta na x e 5
# izpolzwame dwojni kawichki
echo "Using double quotes, the value of x is: $x"
# izpolzwame edinichni kawichki
echo 'Using forward quotes, the value of x is: $x'

Виждате ли разликата? Може да използвате двойни кавички, ако не смятате да слагата и променливи в низът който ще заграждат кавичките. Ако се чудите дали единичните кавички запазват шпациите в даден низ както това правят двойните кавички погледнете следния пример:

xconsole$ mkdir 'hello world'
xconsole$ ls -F
hello world/

Обратно наклонените кавички коренно се различават от двойните и единични кавички. Те не се използват за да запазват шпациите. Ако си спомняте по-рано използвахме следния ред:

x=$(expr $x + 1)

Както вече знаете резултата от командата expr $x + 1 се присвоява на променливата x. Същият този резултат може да бъде постигнат ако използваме обратно наклонени кавички:

x=`expr $x + 1`

Кой от начините да използвате? Този който предпочитате. Ще откриете, че обратно наклонените кавички са по-често използвани от  $(...). В много случай обаче  $(...) прави кода по-лесен за четене. Вземете в предвид това:

$!/bin/bash
echo "I am `whoami`"

Аритметически операции с BASH
bash ви позволява да смятате различни аритметични изрази. Както вече видяхте аритметическите операции се използват посредством командата expr. Тaзи команда обаче, както и командата true се смята че са доста бавни. Причината за това е че шел интерпретатора трябва всеки път да стартира true и expr командите за да ги използва. Като алтернатива на true посочихме командата ":". А като алтернатива на expr ще изпозваме следния израз $((...)). Разликата със $(...) е броя на скобите. Нека да опитаме:

#!/bin/bash


x=8     # stojnosta na  x e 8
y=4     # stojnosta na  y e 4
# sega shte priswojm sumata na promenliwite x i y na promenliwata z:
z=$(($x + $y))
echo "Sum na  $x + $y e $z"

Ако се чуствате по-комфортно с expr вместо $((...)), тогава го използвайте него.

С bash можете да събирате, изваждате, умножавате, делите числа както и да делите по модул. Ето и техните символи:

ДЕЙСТВИЕ             ОПЕРАТОР
Събиране +
Изваждане -
Умножение *
Деление /
Деление по модул %

Всеки от вас би трябвало да знае какво правят първите четири оператора. Ако не знаете какво означава деление по модул това е остатъка при деление на две стойности. Ето и малко bash аритметика:

#!/bin/bash
x=5   # initialize x to 5
y=3   # initialize y to 3

add=$(($x + $y))   # sumiraj  x sys  y i priswoj rezultata na promenliwata add


sub=$(($x - $y))   # izwadi ot  x  y i priswoj rezultata na promenliwata sub
mul=$(($x * $y))   # umnozhi  x po y i priswoj rezultata na promenliwata mul
div=$(($x / $y))   # razdeli  x na  y i priswoj rezultata na promenliwata div
mod=$(($x % $y))   # priswoj ostatyka pri delenie na  x / y na promenliwata mod

# otpechataj otgoworite:


echo "Suma: $add"
echo "Razlika: $sub"
echo "Projzwedenie: $mul"
echo "Quotient: $div"
echo "Ostatyk: $mod"

Отново горният код можеше да бъде нашисан с командата expr. Например вместо add=$(($x + $y)), щяхме да пишем add=$(expr $x + $y), или  add=`expr $x + $y`.



Четене на информация от клавиатурата
Сега вече идваме към интересната част. Вие можете да направите вашите програми да си взаймодействат с потребителя и потребителя да може да си взаимодейства с програмата. Командата която ви позволява да прочетете каква стойност в въвел потребителя е read. read е вградена  в bash команда която се използва съвместно с променливи, както ще видите:

#!/bin/bash


# gets the name of the user and prints a greeting
echo -n "Enter your name: "
read user_name
echo "Hello $user_name!"

Променливата тук е  user_name. Разбира се може да я наречете както си искате. read ще ви изчака да въведето нещо и да натиснете клавиша ENTER. Ако не натиснете нищо, командата read ще чака докато натиснете ENTER . Ако  ENTER е натиснат без да е въведено нещо то ще продължи изпълнението на програмата от следващия ред. Ето и пример:

#!/bin/bash
# gets the name of the user and prints a greeting
echo -n "Enter your name: "
read user_name

# the user did not enter anything:


if [ -z "$user_name" ]; then
    echo "You did not tell me your name!"
    exit
fi

echo "Hello $user_name!"

Ако потребителя натисне само клавиша ENTER нашата програма ще се оплаче и ще прекрати изпълнението си. В противен случай ще изпечата поздравление. Четенето на информацията която се въвежда от клавиатурата е полезно когато правите интерактивни програми, който изискват потребителя да отговори на конкретни въпроси.

Функции
Функциите правят скрипта по-лесен за поддържане. Най-общо казано фумкциите разделят програмаата на малки части. Функциите изпълняват действия, който вие сте дефинирали и може да върне стойност от изпълнението си ако желаете. Преди да продължим ще ви покажа един пример на шел програма която използва функция:

#!/bin/bash

# functiqta hello() samo izpechatwa syobshtenie
hello()
{
    echo "Wie ste wyw funkciq hello()"
}

echo "Izwikwame funkciqta hello()..."


# izwikwame hello() funkciqta wytre w shell skripta:
hello
echo "Weche izleznahte ot  funkciqta hello()"

Опитайте се да напишете тази програма и да я стартирате. Единствената цел на  функцията hello() е да изпечата съобщение. Функциите естествено могат да изпълняват и по-сложни задачи. В горния пример ние извикахме функцията   hello() с този ред:



hello

Когато се изпълнява този ред  bash интерпретатора претърсва скрипта за ред който започва с  hello(). След което открива този ред и изпълнява съдържанието на функцията.

Функциите винаги се извикват чрез тяхното име. Когато  пишете функция можете да започнете функцията с  function_name(), както беше направено в горния пример, или да използвате думата function т.е  function function_name(). Другия начин по-който можем да започнем нашата функция е  function hello():

function hello()


{
    echo "Wie ste wyw funkciq hello()"
}

Функциите винаги започват с  отваряща и затваряща скоба"()", последвани от   отварящи и затварящи къдрави скоби: "{...}". Тези къдрави скоби бележат началото и края на функцията.  Всеки ред с код затворен в тези скоби ще бъде изпълнен и ще принадлежи единствено на функцията. Функциите трябва винаги да бъдат дефинирани преди да бъдат извикани. Нека погледнем нашата програма само, че този път ще извикаме функцията преди да е дефинирана:

#!/bin/bash
echo "Izwikwame funkciqta hello()..."
# call the hello() function:
hello
echo "Weche izleznahte ot  funkciqta hello()"

# function hello() just prints a message


hello()
{
    echo "Wie ste wyw funkciq hello()"
}

Ето какъв е резултата когато се опитаме да изпълним програмата:

xconsole$ ./hello.sh
Izwikwame funkciqta hello()...
./hello.sh: hello: command not found
Weche izleznahte ot  funkciqta hello()

Както виждате програма върна грешка. Ето защо е добре да пишете вашите функции в началото  на скрипта или поне преди са ги извикате. Ето друг пример как да използваме функции:

#!/bin/bash
# admin.sh - administrative tool

# function new_user() creates a new user account


new_user()
{
    echo "Preparing to add a new user..."
    sleep 2
    adduser     # run the adduser program
}

echo "1. Add user"


echo "2. Exit"

echo "Enter your choice: "


read choice

case $choice in


    1) new_user     # call the new_user() function
       ;;
    *) exit
       ;;
esac

За да работи правилно тази програма трябва да сте влезли като root, тъй като adduser е програма която само root потребителя има право да изпълнява. Да се надяваме че този кратък пример ви е убедил в полезноста на фукциите.



Прихващане не сигнали
Може да използвате вградената команда trap за да прихващате сигнали във вашата програма. Това е добър начин да излезете нормално от програмата. Непример ако имате вървяща програма при натискането на CTRL-C ще изпратите на програмата interrupt сигнал, който ще "убие" програмата. trap ще ви позволи да прихване този сигнал и ще ви даде възможност или да продължите с изпълнението на програмата или да съобщите на потребителя, че програмата спира изпълнението си. trap има следният синтаксис:

trap dejstwie signal

dejstwie указва какво да искате да направите когато прихванете даден сигнал, а signal е сигналът който очакваме. Списък със сигналите може да откриете като пишете trap -l. Когато използвате сигнали във вашата шел програма пропуснете първите три букви на сигнала, обикновено те са SIG. Например ако сигнала за прекъсване е SIGINT, във вашата шел програма използвайте само INT. Можете да използвате и номера на сигнала. Номера на сигнала SIGINT е 2. Пробвайте следната програма:

#!/bin/bash


# using the trap command

# da se zipylni funkciqta sorry() pri natiskane na CTRL-C:


trap sorry INT

# function sorry() prints a message


sorry()
{
    echo "I'm sorry Dave. I can't do that."
    sleep 3
}

# count down from 10 to 1:


for i in 10 9 8 7 6 5 4 3 2 1; do
    echo $i seconds until system failure."
    sleep 1
done
echo "System failure."

Сега докато програмата върви и брои числа в обратен ред натиснете CTRL-C. Това ще изпрати сигнал за прекъсване на програмата. Сигналът ще бъде прихванат от trap командата, която ще изпълни sorry() функцията. Можете да накарате trap да игнорира сигнал като поставите  "''" на мястото на действие. Можете да накарате trap да не прихваща сигнал като използвате  "-". Например:

# izpylni sorry() funkciqta kogato programa poluchi signal SIGINT:
trap sorry INT

# nakaraj programata da NE prihwashta SIGINT signala :


trap - INT

# ne prawi nishto kogato se prihwane signal SIGINT:


trap '' INT

Когато кажете на  trap да не прихваща сигнала, то програма се подчинява на основното действие на сигнал, което в конкретния случай е да прекъсне програмата и да я "убие". Когато укажете trap да не прави нищо при получаване на конкретен сигнал, то програма ще продължи своето действие игнорирайки сигнала.



AND и OR
Видяхме как се използват условните оператори и колко полезни са те. Има две допълнителни неща които могат да бъдат добавени. Условните изразите с AND (или "&&") и  OR (или "||"). AND условният израз изглежда по следният начин:

условие_1 && условие_2

AND изразът проверява първо най-лявото условие. Ако условието е вярно се проверява второто условие. Ако и то е вярно се изпълнява останалата част от кода на скрипта. Ако условие условие_1 не е вярно(върне резултат  false), тогава   условие условие_2 няма да бъде проверено. С други думи:



if(ако) условие_1 е вярно, AND(и) if(ако) условие_2 е вярно, then(тогава)...

Ето един пример с AND условие:

#!/bin/bash
x=5
y=10
if [ "$x" -eq 5 ] && [ "$y" -eq 10 ]; then
    echo "I dwete uslowiq sa wqrni."
else
    echo "Uslowiqta ne sa wqrni."
fi

Тук виждаме, че x и y имат стойността за която проверяваме. Променете стойноста на x от x=5 на  x=12, след което пуснете отново програмата и ще се убедите, че условието не е изпълнено( връща стойност false).

OR изразът е подобен. Единствената разлика е, че проверява дали най-левият израз не е верен(т.е връща резултат false). Ако това е изпълнено се проверява следващият израз, и по-следващия:

условие_1 || условие_2

С други думи това звучи така:



if(ако) условие_1 е вярно, OR(или) ако условие_2 е вярно, тогава...

Ето защо кодът след този условен оператор ще бъде изпълнен ако поне едно от условията е вярно:

#!/bin/bash
x=3
y=2
if [ "$x" -eq 5 ] || [ "$y" -eq 2 ]; then
    echo "Edno ot uslowiqta e wqrno."
else
    echo "Nito edno ot uslowiqta ne e wqrno."
fi

В този пример ще се уверите, че едно от условията е вярно. Сменете стойността на променливата y и изпълнете отново програмата. Ще видите, че нито едно от условията не е вярно..

Ако се замислите, ще видите, че условният оператор  if може да замести употребата на AND и OR изразите. Това става чрез използването на вложени if оператори. "Влагане на if оператори"  означава да използваме if оператор в тялото на друг if оператор. Можете да правите влагане и на други оператори, а не само на if. Ето един пример с вложени ifоператори, който заместват използването на AND израз в кода на програмата:

#!/bin/bash


x=5
y=10
if [ "$x" -eq 5 ]; then
    if [ "$y" -eq 10 ]; then
        echo "I dwete uslowiq sa wqrni."
    else
        echo "Uslowiqta ne sa wqrni."
    fi
fi

Резултатът е същия както и ако използвахме AND израз. Проблемът е, че кодът става по трудно четим и отнема повече време за да се напише. За да се предпазите от проблеми използвайте AND и OR изрази.



Използване на аргументи
Може би сте забелязали, че повечето програми в Linux не са интерактивни. От вас се иска да въведете някакви аргументи, в противен случай получавате съобщение в което се обеснява как да използвате програмата. Вземете за пример командата more. Ако не напишете име на файл след нея, резултатът ще бъде точно едно такова помощно съобщение. Възможно е да направите вашата шел програма да използва аргументи. За тази цел трябва да използвате специалната променлива "$#". Тази променлива съдържа общия брой на всички аргументи подадени на програмата. Например ако изпълните следната програма:

xconsole$ foo argument

$# ще има стойност 1 , защото има само един аргумент подаден на програмата. Ако имате два аргумента, тогава $# ще има стойност 2. В допълнение стойноста на всеки аргумент (нулевият аргумент е винаги името на програма - foo) може да се вземе като използвате променливите $0 - за името на програмата в случая foo, $1 за стойноста на първият аргумент -argument и т.н. Може да имате максимум 9 такива променливи от  $0 до $9. Нека да видим това в действие:

#!/bin/bash


# izpechataj pyrwiq argument
# proweri dali ima pone edin argument:
if [ "$#" -ne 1 ]; then
    echo "usage: $0 "
fi

echo "Stojnosta na argumenta e $1"

Тази програма очаква един и само един аргумент за да тръгне. Ако я стартирате без аргументи, или подадете повече от един аргумент, програмата ще изпечата съобщение за това как да се използва. В случай че имаме само един аргумент шел програмата ще отпечата стойноста на аргумента който сте подали. Припомнете си, че $0 е името на програмата. Ето защо тази специална променлива се използва в "usage" съобщението.

Пренасочване и PIPING
Обикновено, когато стартирате дадена команда, резултата от изпълнението се отпечатва на екрана. Например:

xconsole$ echo "Hello World"


Hello World

"Пренасочването" ви позволява да съхраните резултата от изпълнението накъде другаде. В повечето случаи това става към файл. Операторът ">" се използва за пренасочване на изхода. Мислете за него като за стрелка сочеща  къде да отиде резултата. Ето еди пример за пренасочване на изхода към файл:

xconsole$ echo "Hello World" > foo.file
xconsole$ cat foo.file
Hello World

Тук резултатът от командата echo "Hello World" е пренасочен към файл с име foo.file. Когато прочетете съдържанието на файла ще видите там резултата. Има един проблем когато използвате оператора ">". Ако имате файл със същото име, то неговото съдържание няма да бъде запазено, а ще бъде изтрито и заместено с новото. Ами ако искате да добавите информация във файла без да изтривате старата? Тогава трябва да използвате оператора за добавяне : ">>". Използва се по същият начин с тази разлика, че не изтрива старото съдържание на файла, а го запазва и добавя новото съдържание накрая.

А сега ще ви запознаем с piping. Piping-ът ви позволява да вземете резултата от изпълнението на дадена програма и да го използвате като входни данни за друга програма. Piping става посредством оператора: "|". Забележете, че това не е малката буквата "L". Този оператор може да получите чрез натискане на клавиша SHIFT и \. Ето и един пример за piping:

xconsole$ cat /etc/passwd | grep xconsole


xconsole:x:1002:100:X_console,,,:/home/xconsole:/bin/bash

Тук четем целия файл /etc/passwd и след това резултатът е подаден за обработка на командата grep, която от своя страна, претърсва текста за низът   xconsole и изпечатва целия ред съдържащ този низ на екрана. Може да използвате и пренасочване за да запишете крайният резултат на файл:

xconsole$ cat /etc/passwd | grep xconsole > foo.file
xconsole$ cat foo.file
xconsole:x:1002:100:X_console,,,:/home/xconsole:/bin/bash

Работи. Файлът /etc/passwd е прочетен, и неговото съдържание е претърсено от командата grep за низът xconsole. След което крайният резултат е пренасочен към файл foo.file. Ще откриете, че пренасочване и piping  са много полезни средства когато пишете вашите шел програми.



Временни файлове
Често ще има моменти в който ще ви се наложи да създадете временен файл. Този файл може да съдържа временна информация и просто да работи с някоя програма. В повечеето случаи с завършването на изпълнението на програмата се изтрива и временния файл. Когато създадете файл трябва да му зададете име. Проблемът е, че името на файла  който създавате  не трябва да съществува в директорията в която го създавате. В противен случай може да затриете важна информация. За да създадете файл с уникално име трябва да използвате "$$" символа,   като представка или надставка в името на файла. Вземете за пример следния случай: искате да създадете временен файл с име hello. Има вероятност и някой друг да има файл със същото име в тази директория, което ще доведе до катастрофални резултати за вашата програма. Ако вместо това създадете фиайл с име hello.$$ или $$hello, вие ще създадете уникален файл. Опитайте:

xconsole$ touch hello


xconsole$ ls
hello
xconsole$ touch hello.$$
xconsole$ ls
hello     hello.689

Ето го и нашият временен файл.



Връщане на стойности
Повечето програми връщат стоност(и) в зависимост от начина по който завършват изпълнението си. Например, ако разгледате ръководството на командата grep, ще видите, че в него се казва че командата grep връща стойност 0 ако има съвпадение, и 1 ако не е открито съвпадение. Защо да се грижим да връщаме стойности? По много причини. Нека да кажем, че искате да проверите дали конкретно потребителско име съществува на вашата система. Единият от начините да направите това е да използвате командата grep върху файла с паролите /etc/passwd. Да предположим, че потребителското име което търсим е foobar:

xconsole$ grep "foobar" /etc/passwd


xconsole$

Няма никъв резултат от изпълнението. Това означава че grep не е намерила съвпадение. Но може да направим програмата много по-полезна ако се появява съобщение, което пояснява резултата. Това е когато искате да проверите стойноста която се връща от дадена програма. Има една специална променлива, която съдържа крайният резултат от изпълнението на програмата. Тази променлива е $?.Разгледайте следният код:

#!/bin/bash
# grep for user foobar and pipe all output to /dev/null:
grep "foobar" /etc/passwd > /dev/null 2>&1
# capture the return value and act accordingly:
if [ "$?" -eq 0 ]; then
   echo "Match found."
    exit
else
    echo "No match found."
fi

Когато стартираме програмата променливата "$?" ще прихване резултата от командата grep. Ако той е равен на 0, значи има съвпадение и подходящо съобщение ще обяви за това. В противен случай, ще изпечата, че няма съвпадения. Това е един основен начин за получаване на резултата, който връща дадена програма. Ще откриете, че доста често ще ви се наложи да знаете стойността, която връща дадена програма за да продължите по-нататък.

Ако случайно се чудите какво значи 2>&1 сега ще ви обясня . Под Linux, тези номера обозначават файлови дескриптори. 0 е за стандартния вход (пример: клавиатура), 1 е за стандартния изход (пример: монитор) и 2 е за стандартния изход на грешките (пример: монитор). Всяка обикновена  информация се изпраща на файлов дескриптор 1, и ако има грешки те се изпращат на файлов дескриптор 2. Ако не искате тези съобщения да излизат просто можете да ги пренасочите към /dev/null. Забележете, че това няма да спре изпращането на информацията на стандартния изход. Например ако нямате права да четете от директория на друг потребител вие няма да можете да видите нейното съдържание:

xconsole$ ls /root


ls: /root: Permission denied
xconsole$ ls /root 2> /dev/null
xconsole$

Както виждате съобщението за грешка не беше изпечатано. Същото важи както и за други програми така и за файлов дескриптор 1. Ако не искате резултата от изпълнението на програмата да се отпечатва на екрана, можете спокойно да го пренасочите към /dev/null. Ако не искате да виждате както резултата от изпълнението, така и съобщенията за грешка може да го направите по следният начин:

xconsole$ ls /root > /dev/null 2>&1

Това означава че резултата от програмата както и всяка грешка която предизвика тази програма ще бъдат изпратени на /dev/null, така че никога повече няма да можете да ги видите.

Какво трябва да направите ако искате вашият шел скрипт да връща стиойност при завършване на програмата? Командата  exit приема само един аргумент - число което трябва да се върне при   завършване на програмата. Обикновно числото 0 се използва за да кажем, че програмата е завършила успешно, т.е. не е възникнала никаква грешка по време на нейното изпълнение. Всичко по-голямо или по-малко от 0 обикновено обозначава, че е възникнала някаква грешка. Това го решавате вие като програмист. Нека проследим следната програма:

#!/bin/bash


if [ -f "/etc/passwd" ]; then
    echo "Password file exists."
    exit 0
else
    echo "No such file."
    exit 1
fi

Заключение
С това завършихме уводът в bash програмирането. Това ръководство ви дава основните знания за да можете да редактирате чужди bash скриптове или да създавате нови. За да постигнете съвършенство обаче, трябва много да практикувате. bash е идеално средство за писане на обикновени административни скриптове. Но за по-големи разработки ще се нуждаете от мощни езици като C или Perl.

Успех.
Каталог: files -> tu files
tu files -> Увод в компютърната графика
tu files -> Xii. Защита и безопасност на ос
tu files -> Електрически апарати
tu files -> Средства за описание на синтаксиса
tu files -> Stratofortress
tu files -> Начало Решаване на проблеми
tu files -> 6Технологии на компютърната графика 1Модели на изображението
tu files -> Z=f(x), където x- входни данни; z
tu files -> Body name библиотека global Matrix imports (достъп по име) … var m[N, N] := … end decl., proc … resource f final code imports node, Matrix end name var x: node node; if x … Matrix m[3,4] :=: … end


Сподели с приятели:




©obuch.info 2024
отнасят до администрацията

    Начална страница