download.bg
 Вход Списание  Новини  Програми  Статии  Форум  Чат   Абонамент  Топ95   Архив 

Bash (Bourne Again SHell) - приложно програмиране (от един любител и любимия му форум) - v.01

< 1 2 >

Автор
Съобщение
phrozencrew
Пон, 16.11.09, 22:03
Абе не е ли време да напишем едно читаво ръководство за Bash?! Писна ми да чета някакви неща на английски или пък "леко" недоизяснени туторси на български. Ако скочим, както беше оная реклама, ше бутнем и cmd-промпта, дет се вика.
Та по тоя повод почвам едно ръководство, което се надявам с ваша помощ да допълвам и след време да го предложим като статия или малка книжка за официално публикуване.
Бива ли? И да не бива, аз почвам, но това ще е във втори пост, че да може да се редактира на воля!
phrozencrew
Пон, 16.11.09, 22:03
Bash (Bourne Again SHell) - приложно програмиране (от един любител) - v.01

В този урок искам да разкажа за магнетизма на този популярен език, като разчитам за допълване от вас. Като един непрограмист бих нарекъл bash творчески или арт език, защото позволява използването на голямо богатство външни инструменти и дори най-простата задача може да се извърши по много начини. Всъщност истината е, че този език се е използвал от Шекспир за да напише "Хамлет", но пичагата е починал, преди да разкрие тайната на pipe-линията, която е използвал. Няма да се задълбочавам в техническите дълбини, а ще грабна леко от поетизма на езика, колкото да погъделичкам интереса на всеки, който е решил да използва свободните операционни системи. Този разказ ще е от един любител и фен на linux, без да претендирам, че разбирам много от изкуството на програмирането с bash.
Предполагам е ясно, че bash е шел (конзола) по подразбиране на почти всички Linux/UNIX/Mac операционни системи. Добре е да се знае и че има още доста популярни шелове. А най-важното е да се знае, че в тези операционни системи всичко е файл!

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

1. Увод (е стига с тоя увод де!)
2. Променливи
3. Взимане на изход от програма - променлива или... `...` и $(...)
4. Извеждане на резултата - echo и printf
5. Масиви
6. Използване на инструменти, препоръчителни за прохождащи поети на bash
7. Функции
8. Да поциклим (Всички взеха ли си стъкълца? Аре са на паркета, или ръчичките в тостера!!!)
9. test
10. Четене и писане (I/O) от конзолата
11. Специални символи - IFS, [ ], [[ ]], $#, ( ), (( )) ... Или как да се правим, че всичко е шифровано
12. Примерна програмка с база данни
13. Изводи и изход

Точките търпят промени и можете да добавяте всякакъв род предложения. Като започнем от сорта на "Общото между Bash и баш Бирата"

ПРОМЕНЛИВИ

Променливите в bash, както във всички останали езици са части от паметта, които можем да използваме в потока на програмата. Променливите се създават като напишем името на променлива, непосредствено следвана от знака "=" и след това и дадем стойност. Променливите се пишат в слят стринг (сбор от някакви символи), като е желателно да използвате латински букви и долна черта(максимум!). Когато променливата ви е съставена от няколко думи тя трябва да е затворена в единични или двойни кавички. За да видите променлива трябва да и сложите знак за стринг и да я изпълните с команда за визуализиране, като echo (не е единствена). Едва ли сте малоумни, но не ме целете с камъни, постарах се да е ясно. За пример нека запалим един терминал и запишем следните редове в него:
prom=Moeto
MyIP=127.127.127.127
quest=". Kefi6 li, a??"

За да видим какво безобразие сме съхранили в паметта на злощастната ни машина нека напишем следния ред:
echo $prom" IP e "$MyIP$quest

Резултата от по-горната команда е:
Moeto IP e 127.127.127.127. Kefi6 li, a??
Ако сложим целия израз в общи кавички и го изпълним, ще получим същият резултат:
echo "$prom IP e $MyIP$quest"

Какво обаче ще се случи, ако сложим този израз в единични кавички:
echo '$prom IP e $MyIP$quest'

Резултата ще е, че ще получим същия отговор, като въпроса:
$prom IP e $MyIP$quest
Това е особено полезно, когато искаме да покажем даден променлива или специален символ, без да се изпълнява от bash. Разбира се това можем да го направим и по друг начин, като използваме специален ескейпващ символ "\":
echo "\$MyIP = $MyIP"

и разбира се резултата е: $MyIP = 127.127.127.127
Ами какво ще стане, ако искаме да отпечатаме повече символи след променливата, например, ако сме написали echo $MyIPto? Как да кажем на bash, че искаме да се ограничи само до символите на променливата? Интересен въпрос с много елегантен отговор. Bash ви съветва в този случай да сложите, след знака за стринг, променливата в ъглови скобки:
echo ${MyIP}to

резултат:
127.127.127.127to
В тези ъглови скоби можете да задавате и зелени карти (wildcards), които да ограничат каква част от присвоената променлива да се визуализират, но това е вече за много напреднали поети на bash, които са на повече бирички. Все пак ето малко доп.инфо. На този етап това ни е достатъчно за променливите. Но пък как можем да присвояваме стойности на променлива, които са върнати от изпълнение на дадена програма ...

ВЗИМАНЕ НА ИЗХОД ОТ ПРОГРАМА

Bash разполага с два основни начина за изпълнение на програми, като $(programa), `programa`. Но специалистите препоръчват $(programa). Как можем да присвоим изход на променлива от програма? Ще използвам една проста програма, която да ни покаже тази възможност - date. Програмата date връща отговор текущата дата, като самата команда разполага с възможност за форматиране на изхода от изпълнението и, т.е. можем да визуализираме точно тази част от датата, която искаме и то по такъв начин, който ни е удобен. В общия случай:
datata=$(date)
echo $datata

Резултата от изпълнението на командата е:
Mon Nov 16 21:09:44 FLEST 2009
Ако вкараме и малко форматираме, можем да получим чудИса :):
datata=$(date +"%d.%m.%y")
echo $datata

Резултата от изпълнението на командата е:
16.11.09
Разбира се, както казахме по-горе, можем да използваме и странните ляво-наклонени кавички:
datata=`date +"%d.%m.%y"`

Което ще ни върне същият резултат.

Повечето конзолни инструменти в свободните операционни системи връщат резултат, който може да се присвои на променлива. Това е много важно да се знае. Като едни лаици бихме могли да преформатираме и изхода от изхода. Само за гъдел ще чопна единствено датата, която се визуализира от горния скрипт:
den=$(echo $datata | cut -d"." -f2)
echo $den

Резултата от изпълнението на командата е:
(Ако още веднъж използвам по-горния израз ще си прегриза сухожилията на коляното!)
11
Хитро а? :) Нека кажем някои неща за този символ "|". Този символ се използва за навързване на няколко команди, като изхода на предишната се подава като вход на следващата. Това е една много мощна философия и религия от древните времена на UNIX. още от преди родителите ви да са били родени :), че дори преди да сте им били в любовния поглед :). Английското название на този вид навързване се нарича pipeline (тръбна връзка :)). С тази техника можете да навържете десетки окултни инструменти, ако имате нерви. И изобщо голяма забава пада. Но регулярните изрази сложиха край на купона и в момента са популярни pipe-линии от максимум 3-4 инструмента (програми). Абе последно програми ли са или инструменти.. ъ-ъ-ъ или приложения (разбираш ли?!), че нещо не ти следя мисълта. На кой му пука! Кой как му е кеф!

ИЗВЕЖДАНЕ НА РЕЗУЛТАТА - echo и printf

echo

Командата echo има някои интересни свойства, които е редно да се отбележат в нашия туториал. Няма да разглеждам всички възможности, защото можете да използвате man echo, за да разберете повече.
Имайте в предвид, че има огромна разлика дали echo ще се използва с кавички или без кавички. Разликата е, че ако използвате кавички ще можете да използвате и някои специални символи, НО само ако добавите опцията -e към echo.
Основните възможности:
\a - издаване на звук (камбанка)
\c - подтискане на новия ред
\n - нов ред
\r - връщане на каретката (в MAC това е стандарт за нов ред)
\t - хоризонтална табулация

Примери:
$ echo "\n"
n
#нов ред 
 

$ echo -n "\n"
\n

Това в случая е същото като:
$ echo -e '\\n'"\c"
\n

$ echo -e "\n"
#нов ред
#нов ред 
 

Ако обаче не добавите , тогава когато сложите в скоби някоя от по-горните опции, няма да се случи нищо особено, освен принтирането на опцията.
Ако не използвате кавички, ляво наклонената черта ще действа като ескейпващ символ и нищо повече.
Друго интересно е да се знае, че понякога може да се получи пренасяне на нови редове на принтирания в конзолата резултат. Вариант да се избегне това е като се използва опцията -n или -e с \c (в примерите по-горе). Това обикновено се случва, когато имате върнат резултат от изпълнението на друга програма.

Често за по-добра четимост се използва и echo с умишлено пренасяне на нов ред на текста. За да пренасяте използвайте ескейпващ символ "\". Специално за тази възможност няма значение дали текста е в двойни кавички или не.
$ echo Тowa e edin mnogo \
dylyg tekst.

Резултат:
Тowa e edin mnogo dylyg tekst.
Абе тариактска работа!

printf

Е, нашият разказ логично опря и до супер(хипер-мега) полезеният инструмент printf. Този инструмент е замислен като наследник на конфликтното echo от старите времена на UNIX. Проектиран е да създаде комфорт и дава мощен контрол над принтирането в командния ред (CLI-тарикатско име, нали! Като на извънземно :)).
Поетите на повечко бирички ще си помислят, че тука нещо има съвпадък. Ами дам, това е почти същият инструмент като функцията printf() в езика за програмиране C (ах този магьосник, де се е навряла пущината!).
Синтаксис на програмата printf:
printf <форматиране> <аргументи...>

Подробния синтаксис бих го записал по този начин:
printf [<форматиращ елемент едно> <форматиращ елемент две> ...] [<аргумент едно> <аргумент две> ...]

Добре (но не задължително) е да подадем равен брой форматиращи елементи и аргументи!
Типичния изглед е този:
ime=Baio
familia=Baiov
printf "Ime: %snFamilia: %s\n" "$ime" "$familia"

Резултат:
Ime: Baio
Familia: Baiov

Където, според синтаксиса имаме 2 форматиращи елемента (%s и %s) и два аргумента, подадени за форматиране ("$ime" и "$familia").
Въпроса, дали Байо е Зайо или е друго ньедно животно, си го задавайте сами преди лягане. И ако е байо тоя заьо, защо?! Най вече! Аз повече на провокации няма да отговарям!
Естествено, че някой опортюнист са ше каже, -Добре е бай ..ъ-ъ-ъ пичага, ами как ше принта знак процент, а?
Лесно, майна! Просто слагате два броя от тая хава "%%".
procent=85
printf "Tuka malko procent4e: %s%%\n" "$procent"

Резултат:
Tuka malko procent4e: 85%
Нека дадем и малко обяснение за тия проценти, тия кавички и въобще. Системата е следната. Ако не зададете никакво форматиране, то тогава printf ще изпечата всичко, което го накарате и то почти буквално, но с условности. Тогава е добре да ползваме единични кавички, защото, ако използвате двойни, има шанс да настъпите някой специален символ, като "!" например. Затова:
printf 'Pe4atai bukvalno! '$procent%%

Резултат:
Pe4atai bukvalno! 85%
Излиза, че можем да ползваме printf като echo, но трябва да внимаваме със символите. За това пък си има едно %b, което казва на printf да работи като echo. Е това е добре, но какво стана с онова %s. Ще разгледам няколко основни форматиращи инструкции (ще го патентовам тоя израз - форматиращи инструкции, е гати авторитетното!).
%d - Принтираме целочислена десетична стойност.
%i - Това е синоним на по-горното. Прави същото.
%f - Принти стойности с плаваща запетая - 2.35, 0.12546...
%s - Принти стрингове, дет се вика прав текст.
%c - Принти символ
%b - Ей това е много хитро, защото позволява ескейпващи символи.

За другите магии си използвайте man printf.
Кои са основните ескейпващите символи, които можем да ползваме с %b? Същите, както и при echo:
\\ - Принти ляво наклонена черта "\"
\n - Принтира нов ред
\r - Принтира връщане на каретката
\t - Принти хоризонтален табулатор

Сега един пример:
printf "Cifri4ka: %dnString: %snPlavashta zapetaia: %f" 9 "Alooha banda" 3.14

Резултат:
Cifri4ka: 9
String: Alooha banda
Plavashta zapetaia: 3.140000

Има още нещо мнооого важно! При форматирането можете да задавате обхват, в който аргументите да се изпечатат. Да вземем на пример стринга "Alooha banda". Ако искаме да изпринтираме само първите 6 символа можем да зададем следния обхват %.6s:
printf "String: %.6s" "Alooha banda"

Резултат:
String: Alooha

Нека задълбаем още малко. Ако използвате този формат за числата с плаваща запетая (%f), тогава ще можете да се възползвате и от математическото закръгление на числата. Пример:
printf "Float: %.2f" 3.145

Това ще върне закръглението:
Float: 3.15

Останалото е история! Ех, че прозаично. Само дето пиша глупости. Останалото е много упражнения и лекинко попрочитане на man или info.

МАСИВИ - bash arrays

Както в останалите езици за програмиране и bash поддържа работата с масиви (arrays). С ограничението, че масивите са едномерни, поне за версиите до сега. Може би на някой няма да му е ясно какво точно представлява един масив, за това ще се опитам да обясня с метафора. Да вземем на пример един домат - ей това е масива :). И после го изяждаме. Е може и на салатка да си го нарежем, а с една тънка мастичка... малиии.
Майтапя се! Та да вземем за пример една пазарска чанта - масив. И започнем в нея да слагаме някакви продукти - елементи на масива. Така погледнато декларирането (някои поети биха използвали инициализиране) на този масив в bash би изглеждало така:
chanta=("birichka" "rakijka" "mastichka" "krastavichka")

NB! Масивите могат да се обявят без скоби, a и без кавички, но в скоби, ако са цели думи, но така е по-културно.
Само дето това си е пълна чанта с бая алкохол в нея, т.е. не я пълним, а си я поръчваме пълна. Абе днеска да не е празник нещо или е пятница? А честито!
Как ли можем да видим всичкия амбалаж, който сме сложили в нея, като използваме малко магия с ъглови скоби и други рунически символи:
echo ${chanta[@]}

Резултат:
birichka rakijka mastichka krastavichka

Същият резултат ще постигнем и с заклинанието ${chanta[*]}, т.е. ако сменим кльомбата с астерикс.
Разбрахме как да си вземем пълна чанта, и как да видим какво е сложено в нея, но да видим как можем да добавяме допълнителни елементи. В случая, с това хубаво пиене не можем да не сложим и малко маслинки в чантата. Добавянето на елемент към масива става по следния начин:
chanta=(${chanta[@]} maslinki)

Ако държим да сме мега-изрядни би трябвало да сложим и малко кавички, но за сега не е задължително. Все пак това ще е по-правилно:
chanta=("${chanta[@]}" "maslinki")
echo ${chanta[@]}

Резултат:
birichka rakijka mastichka krastavichka maslinki

До тук добре, обаче с тая ракийка ще я втасаме, та за това викам да махнем поне нея. Как се маха елемент от масив:
unset array[1]

Командата unset премахва елемент от масив, тя може да премахва и променливи, че дори и целият масив, стига да напишем заклинанието unset chanta.
Добре, но защо махнахме елемент едно, след като ракийката в списъка "chanta" е втора под ред? Естествено защото всяко броене в компютърния свят започва от нула "0". Затова първи номер в списъка е chanta[0]=birichka. Добре запомнете с кое да започнете купона :)!
Естествено има и друг начин да изтриете елемент от масив, просто като го приравните към нищо chanta[0]= .

Друго интересно нещо, което бихме искали да знаем е колко общият брой на продуктите в чантата, или елементите в масива. Това също става с едно простичко и логично заклинание ${#МАСИВ[@]} или ${#МАСИВ[*]}. В нашия случай ще изглежда така:
echo "Broi produkti w chantata: "${#chanta[@]} 
 

Резултат:
Broi produkti w chantata: 4

Можем да правим и други магарии с масивите, например можем бързо да видим индексите на масива ни ${!chanta[*]}, което сега ще върне 0 1 2 3.

Мисля, че за сега това е напълно достатъчно знание за масивите, за да си направим поемата.

ИНСТРУМЕНТИ, КОИТО Е ДОБРЕ ДА ПОЗНАВАМЕ

Основните инструменти, които се използват с bash (и другите шелове) са събрани в един пакет наречен coreutils. Този пакет пък от своя страна се дели на още няколко секции - textutils, shellutils, fileutils и т.н. Тъй като това е съвкупнст от десетки инструменти, които едва ли ще ви се наложи да ползвате, ще се огранича до семпло описание само на няколко по-популярни. Понякога може да ни се случи да забравим как точно се изписва дадена команда. Тогава за посещане можем да използваме клавиша TAB, като изпишем поне първата буква на команда и после натиснем TAB. Обикновено се натиска 2 пъти, но зависи от дистрибуцията, която ползваме. TAB ще ни върне всички инструменти, които започват с буквата или буквите, които сме изписали.

info

За да поучите информация за някой от инструментите в coreutils можете да използвате командата info coreutils следвана от името на инструмента:
info coreutils ls

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

'ls': List directory contents
=============================

   The 'ls' program lists information abo...
   ...
* Menu:

* Which files are listed::
* What information is listed::
* Sorting the output::
* More details about version sort::
* General output formatting::
* Formatting file timestamps::
* Formatting the file names::
...

Тези редове, които започват с астерикс "*" са линкове и дават подробна информация за опциите с които разполага дадения инструмент. За да посетите някой линк идете с курсора до него и натиснете Enter. Превъртане на страницата надолу и нагоре се прави с клавишите "Page Down" и "Page Up". Отваряне на следваща страница - с клавиш "n", предишна страница - клавиш "p". Връщането на главната страница става с бутона "u".

ls

Накратко командата "ls" листва (извежда в списък) съдържанието на директориите. Ако искаме да листнем директория, която се намира някъде си, тогава пишем или абсолютният път, или релативният път до нея:
ls /absoliuten/pyt/
ls ../relativen/pyt

../ - това ни извежда една директория по-горе
./ - това ни дава текущата директория
/ - с това се отбелязва кореновата директория на операционната система. Както в Winblows имаме C:\, така и тук имаме "/". Сравнението е много неподходящо, но не се сещам как може да се листне My Computer в Win.

chmod


Както споменахме в началото, всичко в Linux/UNIX е файл, независимо дали става дума за директория, хардуер или нещо друго. Затова след като се запознахме с ls нека видим още един много важен инструмент:
chmod - сменя правата за достъп до файл. Това не се отнася до символните линкове! За да видим какви са правата за достъп до файловете в текущата директория можем да използваме:
ls -l

Резултат:
total 1
-rwx------+ 1 bob users 680 Feb 17  2009 if.sh
drwx------+ 2 bob users   0 Nov 16 13:13 split

В началото на всеки ред забелязваме странни символи от сорта на "drwx------+". Първият символ казва дали това е директория (d) или файл ("-"). След това символите се разглеждат по тройки. Първата тройка символи показва правата върху файла на потребителя (собственика на файла). В случая имаме rwx, което означава, че потребителя може да:
r - чете файла
w - записва във файла
x - изпълнява файла

Втората тройка символи показва правата на групата, а третата тройка правата на всички останали.
Ако искаме да позволим изпълнението (execute) на някой файл от всички потребители, тогава можем да му сменим правата по този начин:
chmod +x file.sh

Ако го приложа за файла if.sh от по-горе, тогава ще имам следния резултат:
-rwx--x--x+ 1 bob users 680 Feb 17 2009 if.sh
Ако искаме да дадем право на групата да го чете, тогава трябва да направим следното:
chmod g+r if.sh

Както виждаме групата се отбелязва с "g". Да видим всички възможности:
u - Потребителят, собственика на файла.
g - Групата, към която принадлежи собственика на файла.
o - Останалите.
a - Всички.
По принцип, когато даваме права за всички, тогава няма нужда да пишем "a". За това и по горе написахме само +x.
Когато искаме да отнемем права, тогава използваме знака минус "-".
chmod a-x if.sh

Така направихме файла неизпълним за всички.
За директории също можем да използваме chmod. Ако искаме дадена директория да може да се листва само от потребителя и групата, тогава правим следното:
chmod a+r direktoria
chmod o-r direktoria

Това може да се направи още по-лесно, ако използваме цифровия формат на командата, но мисля, че няма нужда да усложняваме толкова урока.

cd

Тази команда ни помага да сменяме текущата директория и да се шляем насам-натам. Също, както и при "ls" и тук можем да сменяме директорията като използваме абсолютен или релативен път. Разполагаме и с възможност за телепортиране, като например:
cd ~

Това ще ни закара директно в home директорията на потребителя с който сме се регнали в системата. Командата е същата, както и в Dos.

cat

Тази команда ще отпечата съдържанието на даден текстови файл:
cat text.file

Ако файла е по-голям и не се събира на монитора, тогава можем да използваме командата less в piping-режим:
cat text.file | less

less

Тази команда връща резултата от предишната команда страница по страница. С шпацията или PageDown можем да прелистваме следващата страница. С "q" прекратяваме изпълнението на less. Може да се използва за всеки интрумент, който връща списък или просто по-дълъг текст. Подобенен е на командата "more" в Dos.
ls ~/Desktop | less

Други интересни команди, свързани с правата за достъп и е добре да се познават поне бегло са - groupadd, useradd, chown.

sudo - Super User Do. Прави се от root-а (администратора). Команда, която ви дава права на супер потребител, който може да прави каквото си иска. Верно, че не съвсем понякога, щото нема да стане: sudo sipi-ena-rakia tuka :)

Още малко инфо за файловите команди:
mkdir - прави директории
rm - трие
cp - копира
move - мести от едно място на друго
touch - създава файл с аргумента на командата. Например: "touch me" ще създаде файла "me" в текущата директория.
pwd - полезно, показва ни къде се намираме в момента
vdir - това е "ls" на стероиди :)

Разни други команди:

wc - брои:
wc -W думи,
wc -l редове или
wc -m - букви във файл.
tac - същото като cat, но извежда файла или стандартният вход от долу нагоре

cal - календар. Ако искате да изкарате календар за цялата 2010-та: "cal 2010"

Мрежови команди
ifconfig - извежда информация за IP-то и параметрите на връзката (MAC-адрес и т.н.)
iwlist scan - сканира за мрежи, които са в обхвата на Wireless-a

du - Показва използване на харда от всеки файл и директория в текущата.
ps - извежда процесите. Пример "ps aux"
sort - инструмент за сортиране. Разполага с богат набор опции. Примери:
sort -n - сортира по числова стойност
sort -u - сортира и изкарва само уникалните редове
sort -r - реверсивно сортиране, на обратно
head - извежда първите 10 реда от файл или стандартен вход. Обикновено върви с параметър колко реда да изкара "head -5" - ще изкара 5 реда.
tail - извежда последните 10 реда от стандартния изход (от команда) или файл. Също върви с броя редове. Пример с използването на двете команди head и tail (извеждане на 20-те най-големи директории в текущата):
du | sort -n | tac | head -20
du -xk | sort -n | tail -20

Търсене за файлове и директории
whereis - бързо намиране на файл
locate - бързо намиране на файл или директория
find - бавно намиране на файл :). Пример:
find . -name "*.txt"

lshw - Да видим всичкия хардуер. Да запазим информацията във файл:
sudo lshw -html > hardware.html

arch - в някои дистрота можете да ползвате и този инструмент за листване на хардуера

history - извежда подадените команди в конзолата. За това си трябва отделен урок.
Работа с дискове - CD и ДЖД
Създаване на ISO-файл от CD или DVD:
mkisofs -r -o image.iso /cdrom

изтриване на презаписваем RW-диск:
cdrecord -v dev=/dev/cdrom blank=fast

Рестартиране на системата:
shutdown -r now

Спиране на системата:
shutdown -h now

ЗАБАВА
apt-get moo - просто го пробвайте :)

-==[]==--

lsb_release -a - връща информация за дистрибуцията. Тази информация може да се види и по други начини. Например: cat /etc/issue, cat /etc/lsb-release. Командите са тествани под Ubuntu. Под RedHat може да се използва командата cat /etc/redhat-version.

uname -a - ще изведе информация за версията на кернела, типа ОС, датата и платформата - 32 или 64 битова.
uptime - дава информация за времето в което машината е била включена, както и точния час в който е била включена.
uptime 
#Резултат: 19:23:35 up  1:14,  2 users,  load average: 0.21, 0.06, 0.02 
 

wget - супер универсален доунлоадер с изключително много възможности. Може да се използва за сваляне на файлове, за дърпане на сорс на Web страници, създаване на огледален образ на отдалечена директория или сайт, сваляне на сайт за офлайн-браузване, по време на свалянето абсолютните линкове се конвертират в релативни и т.н. Примери:
Сваляне на HTML сорс кода на някоя страница:
wget -q -O - download.bg

Сваляне на ISO-файл. Когато се свалят големи файлове има вероятност връзката да умре. Тогава за да продължим свалянето от там до където сме стигнали можем да използваме опцията -c (continue):
wget -c http://nimue.fit.vutbr.cz/slax/SLAX-6.x/slax-6.1.2.iso

history - извежда списък с последните 500 команди, изпълнени в конзолата. Броя на командите, които са съхранени зависи от конфигурацията на bash. Ако искаме да намерим определена команда и си спомняме само част от нея, можем да използваме grep:
history | grep "ls"

convert - конвертиране на изображения от един формат в друг:
convert pic.png pic.jpg

prename - преименуване на файлове, като могат да се използва Perl регулярни изрази. Напоследък тази функционалност е добавена направо в инструмента rename.

sleep - изчакване за определено време. Много използвана команда. Формата е:
sleep число[smhd] s - секунди
m - минути
h - часове
d - дни

Тази команда ще накара bash да изчака 5 секунди преди да продължи:
sleep 5s

expr - принти резултат от израз. Този израз може да бъде математически или логически. Позволява сравнява на стрингове. Пример:
expr 3 != 2

Това ще върне 1 - истина.
Други примери за expr:
expr 1 + 3
expr 2 - 1
expr 10 / 2
expr 20 % 3
expr 10 \* 3
echo `expr 6 + 3`

seq - броене със стъпка (seq [от] [стъпка] [до]). Пример:
seq 2 2 20

Ще брои от 2 до 20 със стъпка 2: 2, 4, 6, 8...
Тази команда често се ползва в цикли, където е много полезно стъпковото и броене.
for i in `seq 1 10`; do echo $i; done;
#същото като
seq 1 10 | while read i; do echo $i; done;

В някои дистрота seq е в компанията на jot ([от] [до] [стъпка]).

{a..z} - броене в обхват. Не се сещам как да го обясня по-правилно. Пример:
echo {a..z}
#Резултат: a b c d e f g h i j k l m n o p q r s t u v w x y z 
 

Подходящо е да се използва в комбинации с групи от символи. Да видим как ще получим всички възможни двусимволни комбинации от a до z и числата 1 и 2:
echo {a..z}{1..2}

xargs - обработва аргументите подадени от предната команда. Може да се използва с обхватното броене. Пример:
echo {a..m}{a..m} | xargs -n1

Тази команда е много полезна и определено съветвам на нея да се обърне особено внимание.

tr
Съкращението на тази команда идва от translate. Можем да използваме командата като заместител, т.е. да заместим едни символи с други. Да видим как ще заместим големите букви с малки в някой стринг:
echo ALooHa | tr '[A-Z]' '[a-z]'
#Резултат: alooha 
 

или да заместим цифри с букви:
echo {1..4} | tr '[1-9]' '[a-z]'
#Резултат: a b c d 
 

На командата може да се подаде файл със символа "<":
tr '[A-Z]' '[a-z]' < file.txt

Можем да използваме и опцията "-d", която ще изтрие намерения шаблон. Да видим как можем да конвертираме DOS/Windows текстов файл до UNIX текстов файл:
tr -d '\r' < dos_file.txt > unix_file.txt

cut
cut - отпечатва избрани части от стандартния вход. Тази команда може да работи в три режима, като най използваните са "-f" - обхватен и "-c" - символен. За да разбере, кои части от подадения ред да извлече, използва делиметър (разделител). Ще се опитам да покажа как функционира тази изключително полезна команда. Да разгледаме за начало по-елементарния начин на употреба - символния:
echo "123456789" | cut -c -5
#Това ще върне: 12345
 
echo "123456789" | cut -c 5-
#Това ще върне: 56789
 
echo "123456789" | cut -c 3-7
#Това ще върне: 34567
 
echo "123456789" | cut -c 5
#Това ще върне: 5 
 

При рязането на символи имаме точно определен шаблон, чрез който режем от стринга.

По интересен е обхватния режим на работа с командата - "-f". При този режим можем да използваме входящ и изходящ разделител "-d". Ако не използваме входящ разделител (делиметър), тогава ще имаме режим много подобен на символния от по-горе. Важно е да се знае, че при обхватния режим разделителя (делиметъра) по подразбиране е табулацията - "\t". Да видим един пример:
echo -e "1\t2\t3\t4\t5" | cut -f 3-
3    4    5

Тук режем всичко от третата част нататък.
Сега да видим и малко примери с входящ делиметър "-d":
echo "1|2|3|4|5" | cut -f 1,2 -d \|

Ако не поставим ескейпващия символ "\", ще влезем в pipe-режим, заради pipe-символа "|". За това и избрах толкова интересен пример. Разбира се, определено ще ни трябва да преформатираме изхода и да премахнем тази "тръба", за това ще добавим - "--output-delimiter=". На какво ще е равен този изходен разделител зависи от нашия избор.
echo "1|2|3|4|5" | cut -f 1,2 -d \| --output-delimiter=,
#Резултат: 1,2 
 

По подобен начин можем да видим и home директорията на всеки потребител на системата. В този случай ще използваме директно четене от файл ред-по-ред:
cut –d: -f1,6 /etc/passwd
#Резултат: user1:/home/user1
#user2:/home/user2 
 

cut има и опция да показва само редове, които съдържат разделителя, като пропуска останалите. Това става с опцията "-s".

paste - поставя в линия два или повече файла. Какво имам в предвид. например имаме file1, който се състои от следните редове:
1
2
3
4

Имаме и file2, който се състои от:
edno
dve
tri

Ако използваме paste, за да свържем двата файла, ще получим следният резултат:
paste file1 file2
1       edno
2       dve
3       tri
4

При тази команда, както и cut, можем да използваме делиметър (разделител):
paste -d' ' file1 file2

read
С тази команда можем да четем. Обикновено четем данни въведени от потребителя:
echo -n "Vasheto ime :"; read ime; echo "Priatno mi e $ime!"

read се използва често и в командите за циклене, с които ще се срещнем на по биричка с картофки след малко. Ето едно примерче за стимулиране на стомашно-чревния тракт :):
info cat > cat.info
while read line;do nl; echo -e $line"\n"; done < cat.info

В резултат имаме номерирани редовете от помощната информация за командата cat. Да обясним важното:
while read line; do ... done < cat.info - Това преведено на нашенски значи "Докато четеш всеки ред от стандартния вход < cat.info, вземи да присвоиш всеки ред на променливата line".

Работа със стандартния изход и грешки.

При работа със конзолата често ще се налага да записваме във файл информация от изпълнението на дадена команда. Тази информация се нарича стандартен изход. Когато се получи грешка в изпълнението на даден скрипт или команда можем да запишем във файл и стандартния изход за грешки. Тези 2 типа изход се отбелязват и използват с определени символи. Стандартния изход е ">" или "1>".Стандартния изход за грешки е "2>". Понякога се налага да обединим стандартния изход и стандартния изход за грешки в един файл - "2>&1". Това обединяване пък често се използва за да съхраним информацията в нищото и да получим само потвърждение дали командата е успешна или не:
info cat > cat.info 2> /dev/null

Стандартния вход е много лесен за ползване: "< file"

grep
grep - инструмент за търсене на съвпадение във всеки файл или в стандартния вход. МНОГО, МНОГО ВАЖЕН ИНСТРУМЕНТ. Формата на тази блестяща команда може да се изрази по този начин:
grep [опция] "дума-за-намиране" {файл-или-стандартен-вход}

Някои популярни опции при използване на grep са:
-v - избира несъвпадащи редове
-P - ШАБЛОНА е Perl регулярен израз
-i - игнорира малки или големи букви
-n - показва реда на който се среща шаблона
-c - прави само броене на редовете в които се среща шаблона
-o - Връща като отговор само обхвата на шаблона, без да показва целия ред. Много полезна опция!

grep може да се използва по няколко начина, като възможностите му се разширяват от вграденото разпознаване на WildCards (зелени карти), RegEx - Regular Expressions (регулярни изрази), POSIX регулярни изрази, стандартно търсене на текстов стринг. Да се напише всичко за тази команда ще са необходими много думи и примери. А изучаването и изисква продължително тестване, за да се постигне прилично ниво на владеене на командата. Все пак ще се опитам да покажа някои по-стандартни техники, за да си пийвате спокойно биричката и да работите с grep, така че да скътате работата.
Много разпространено приложение е извличане на синтезирана информация за други команди. Това ще го приложа върху хелпа на grep. Например искаме да се подсетим коя е опцията за да използваме командата с Perl съвместими регулярни изрази (PCRE):
grep --help | grep Perl
#Резултат: -P, --perl-regexp         PATTERN is a Perl regular expression 
 

Това е много основно и полезно приложение. Можем да ползваме този директен подход и за да убием някой процес, който според нас прави гадости. Например искаме да намерим кой е PID-a на всички bash процеси:
ps aux | grep bash

Да видим кои процеси използват най-много процесорно време. За тази цел ще използваме командния език awk и 2 регулярни израза "^" и "[^..]":
ps aux | awk '{print $3"\t"$11}' | grep ^[^0]

Можем да използваме grep и за да си припомним команди, подадени в конзолата:
history | grep "grep"
history | grep -i ps

Да видим кой е с права на root за системата:
grep root /etc/passwd

Да видим обаче един много интересен пример. Да се опитаме да извлечем всички ъпдейтнати програми от началната страница на download.bg - хитро а?!
wget -q -O - http://download.bg | grep -o -P '=12\>[0-9a-zA-Z .]*' | cut -d'>' -f2
#Резултат: Addax P2P 3.6.1.0
#Internet Cyclone 1.99
#twhirl 0.9.4
#The Form Letter Machine 1.11.01
#DOFUS 1.29
#PowerDVD 9.0.2201.0
#... 
 

Да вкараме малко обяснение на това, което направихме:
1. Сваляме с wget страницата и принтираме HTML-сорса на стандартния изход
wget -q -O - http://download.bg
2. Задаваме с пайп "|" на grep да обработи стандартния вход, като му задаваме опция "-o" да принтира само отрязъка на шаблона, а не целия ред. Задаваме му да използва и Perl-съвместими регулярни изрази "-P". След изграждаме самия регулярен израз, което правим след като сме разгледали сорс кода на index страницата на http://download.bg/. Там виждаме, че изброяването на всички ъпдейтнати програми става с:
<img src='img/upd.gif' border=0 width=22 style='margin-right:3px;' height=12>Addax P2P 3.6.1.0</span>

Чудесно и тъкмо за нас :). Един бърз сърч ни дава, че "height=12" се среща само в секцията с ъпдейтнатите програми. Следван от името на програмaта, случая "Addax P2P 3.6.1.0" и най-накрая "<span>". Преглеждаме програмит и виждаме, че са съставени само от букви, цифри, точки и шпации. Задаваме регулярния израз да търси за тези символи - [0-9a-zA-Z .]. Задаваме с астерикс "*" да търси за "0" или повече съвпадения на символите.
3. С cut слагаме делиметър ">" и извличаме само втората част на стринга - т.е. името на програмата:
cut -d'>' -f2
Ако сме майстори-поети и сме на 2-3 бирички, по-горния скрипт бихме могли да го оптимизираме така:
wget -qO - http://download.bg | grep -oP '2\>[\d\w .]*' | cut -d'>' -f2

Интересни примери с grep могат да се видят на много места в мрежата. Можете да потърсите с "grep examples", "grep tutorials" или нещо подобно.

ЗАБАВА
Пробвайте една забавна игра с думи:
sudo apt-get install fortune-mod
echo;fortune;echo

Сега по необясними причини ще изпреваря планирането и ще ви запозная с...

sed

sed е поредния култов инструмент в нашата статия. Толкова е култов, че чак да ти се схванат глезените! По култов е и от "луннта диета за отслабване"! Е не е по-култов от биричката, обаче да пишеш за sed и да си мъцкаш биричка си е мега-култово.
По същество това е редактор за поточен текст. Обаче тоя редактор разполага с възможност за използване на регулярни изрази (Regular Expressions или RegEx). Ще разгледаме някои приложения на sed, макар, че е най-добре да съчетаем примерите с циклите. Но за цикленето по-късно.
Най-известната команда за sed е субституцията(замяната), която се използва с оператора "s":
echo den | sed s/den/nosht/

Този израз ще замести деня (den) с нощ (nosht).
Но какво значи поточен (стрийм) редактор, ако не можем да го приложим за файлове?! Както казахме по-горе, за да вмъкнем за обработка текстов файл, използваме знака "<" (стандартен вход - stdin), а за да запишем резултата от обработката от конзолна команда в текстов файл използваме знака ">" (стандартен изход - stdout). В този случай бихме могли да използваме този UNIX синтаксиса <old >new за да заменим символите от един файл и да запишем промените в друг файл. Прилагайки по горния израз за деня, върху файлове, ще получим:
sed s/Deniat/Noshtta/ <old >new
#Файла old е с съдържание:
#Deniat nastypva s purpurna voiska.
#Резултата е , че файла new съдържа:
#Noshtta nastypva s purpurna voiska.
#Което си е направо раомантично 
 

Вероятно се досетихте, че синтаксиса на sed, в тези случаи е:
sed [оператор]/оригинал/замяна/
Като оригиналния стринг и шаблона за замяна са разделени от дясно наклонена черта "/". Избора на разделите е абсолютно произволен! Можете да използвате и "щрихт но морн" :) (Пуцай Куме!) или пък кльомба @ (абе кой я измисли тая дума?), или пък тръбите, дето толкова ги говорихме "|". Все тая е какво ще използвате за разделите на изразите, важното е да предпазите замяната от разпознаване на символ, за разделяне! Ако използвате "/", тогава в шаблона за замяна трябва да укажете на sed да приеме този символ като част от стринга. Това се прави с ескейпващ символ "\":
echo delimo/delitel | sed 's/delimo/delitel/del/delit/'

В този случай поставете целия израз на sed в единични или двойни кавички. Рядко ще се наложи използването на наклонени черти, но все пак е интересно да го има като вариант.

Да боцнем 2 маслинки с глътката мастичка и да разгледаме по-интересните възможности на мистър sed.

- Използване на & като съвпадащ стринг
Понякога се налага да добавим допълнителни символи към търсения текст. Например да поставим скоби на текста, който ни интересува. По стандартния начин бихме могли, ако знаем точно кой текст търсим, да използваме директна замяна, без регулярен израз:
sed 's/nosht/(nosht)/'
Но това не би ни свършило работа за по-сложни изрази, за това хитрците са измислили добавянето на специалния символ "&". Малко абстрактно звучи, за това да покажем един пример:
sed 's/[a-z]*/(&)/'

В този случай съдържанието на стринга, който съвпада с търсенето се заменя от "&". И още нещо още по-яко. Това заместване може да се прави многократно:
echo 'nosht 1253' | sed 's/[a-z]*/& &/'
#това ще върне:
#nosht nosht 1253 
 

Регулярният израз [a-z] замества цялата латинска азбука с малки букви - от "a" до "z". Знакът астерикс "*" казва на регулярната машина да търси за нула или повече елементи за замяна.

Опиянени нека видим и малко от хелпа на sed-иструктършънопредатора (ба*ти думата, много съм горд от нея):
Sed редактиращи команди
a\ Добави текст под текущата линия.
c\ Промени текста от текущата линия.
d Изтрий текста.
i\ Добави текст над текущата линия.
p Принтирай текста до стандартния изход.
r Прочети файл.
s Търсене и замяна на текст. Субституция.
w Запиши до файл.

Sed опции
-e SCRIPT Добави командите в СКРИПТ-а до набора от команди, които обработват входния текст.
-f Добави командите в СКРИПТ-файла до набора от команди, които обработват входния текст.
-n Заглушен режим.
-V Покажи версията.

Да забием само за адреналина и един интересен пример, който обработва изхода на ls:
ls -l | sed s/^-[-rwx]*/Файл:/ | sed s/^d[-rwx]*/Каталог:/

[AWK - ВЛАСТЕЛИНА НА ТЕКСТОВЕТЕ]

Awk е малък, бърз и разбираем език. Той е ориентиран към работата с текст и може да прави почти всичко, свързано с текстообработка, като запази леснотата на работа, за разлика от много други езици.
Най-честата употреба на awk е свързана с обработката на колонно ориентирани текстове, като таблици или обработка на стандартния вход. Езика има набор от вградени променливи, които допълнително улесняват обработката. Някои от тези променливи $1, $2, $3 и т.н. представят първата, втората, третата и т.н. колона от подадения текст. Например, за да покажем втората колона от файл, можем да използваме следния awk-скрипт:
awk < file.txt '{ print $2 }'

Това означава "от всяка линия принтирай втората колона". Ако файла "file.txt" е със следното съдържание:
red1kolona1	red1kolona2	red1kolona3	red1kolona4
red2kolona1	red2kolona2	red2kolona3	red2kolona4
red3kolona1	red3kolona2	red3kolona3	red3kolona4

Изпълнението на по-горната команда ще върне:
red1kolona2
red2kolona2
red3kolona2

Вероятно се досещате какво би се случило, ако изпълним следната команда:
awk < file.txt '{ print $2, $3 }'

Awk работи на принципа на базите-данни. Ако разберете логиката му, лесно ще можете да пишете собствени бази данни почти на всеки език, за който се сетите. Но нека обясним какво е имала предвид алкохолната ми мисъл по-горе.
Awk сплитва (разделя) стринга, който му подавата по определен критерий. По дефиниция този критерий са празните пространства, като шпация и табулация. Но, според случая, можете да замените този критерий с всеки символ или комбинация от символи. Това правим с опцията -F. Ако файла ни file.txt се състои от следните редове
red1kolona1:red1kolona2:red1kolona3:red1kolona4
red2kolona1:red2kolona2:red2kolona3:red2kolona4
red3kolona1:red3kolona2:red3kolona3:red3kolona4

За да извлечем само втората колона, ще използваме следната команда:
awk <file.txt -F: '{ print $2 }'

Хм, пивко, обаче тоя делиметър "-F:" не ни е съвсем достатъчен. Има още един начин, чрез който можем да посочваме кои са разделителите - FS (field separator). Този field-сепаратор поддържа регулярни изрази и други извънземни неща. Можем да поискаме да извършваме и някакви математически операции с числата от втората колона. Останала ми е повечко салатка за още една тъъънка мастичка, така, че нека задълбаем по-дълбоко. Хипотетично да си представим, че искаме да умножим двете числа от втората колона. Awk, като един любим език на пиячите на бира, си поддържа доста приличен набор от аритметически оператори, от които най-брутално ще се възползвам. Значи искаме да умножим числата от втората колона, т.е. 1*2, 2*2, 3*2. Да умножаваме:
awk <file.txt -F: '{ print $2 }' | awk 'BEGIN {FS="red|kolona"} { print $2*$3 }'

Резултат:
2
4
6

Както всички останали команди в Linux и AWK може да приема директно от стандартния вход, а не само от файл.
echo 5 4 | awk '{ print $1 + $2 }'
// Получаваме 9

Можем да използваме AWK, за да преименуваме всички файлове с дадена директория. Например, ако имаме директориятаfile_list със следното съдържание:
birichka
rakijka
mastichka

Можем да преименуваме всеки от тези файлове, като му добавим някакво разширение, примерно "daj_"
ls | awk '{print "mv "$1" daj_"$1}' | sh

Резултат:
daj_birichka
daj_mastichka
daj_rakijka

Не е задължително да се пият точно в тази последователност. Ако сте много жадни, можете да си ги смесите в едно тънко 200-грамово коктейлче. Всъщност биричка с ракийка (съотв. мастичка с биричка) е малко гнус, обаче ако булката ви е купила по по грешка от оная биричка Redler с лимон, може и да се получи нещо по прилично на вкус. Кой каза "Нааааздравееее"! Мерси, да ви се връща!

Вградени променливи в AWK

По-горе се сблъскахте с няколко вградени променливи, като $1, $2, $3 и т.н., FS. Всъщност списъка с вградени променливи в AWK не е особено дълъг, но някои променливи въобще няма да ви се наложи да ги разбирате. Ето по-популярните:
FS - Field separator
OFS - Output field separator
RS - Record separator
ORS - Output Record separator
FNR - The input record number in the current input file
NR - Number of input records
NF - Number of fields in the current input record
FILENAME - Name of the file that awk is currently reading
FNR - The current record number in the current file
length - брой символи. По дефиниция връща дължината на реда

Башка от това, някои от споменатите променливи поддържат и разширени възможности. Примерно:
$NF - връща последната поле от текущия ред
$0 - връща целия ред. Примерна програмка с $0, която проверява дължината на редовете и ако са по-дълги от 30 символа ги показва:
awk <tmp.txt '{if(length>30){print $0}}'

Повече информация за вградените променливи (за gawk): http://www.gnu.org/software/gawk/manual/html_node/Built_002din-Variables.html

Естествено в AWK могат да се декларират и собствени променливи, такива каквито се гизползват и в другите езици. Декларирането на променлива е супер елементарно "var=value".
Простичко примерче, което събира всички числа от даден ред. Ако имаме файла list.txt със следното съдържание:
1 2 3
2 4 6
8 4 6

Можем да вкараме променлива "tot", която нараства със сбора на всяко поле:
awk <list.txt '{ tot=0; for (i=1; i<=NF; i++) tot += $i; print tot; }'
// Rezultat:
// 6
// 12
// 18

Блокове

AWK поддържа няколко вида блокове от код, които могат да се управляват. Примерно може да се бацне един END, който означава "извърши това, след като всичката обработка в блока е приключила". Ако използваме по-горния файл list.txt и искаме да намерим средно аритметичната стойност на всички числа от първата колона ((1+2+8)/3), можем да напишем следната програмка:
awk <list.txt '{ tot += $1; n += 1; }  END { print tot/n; }'
// Rezultat: 3.66667

Ето още един пример, където събираме само последните полета:
awk <list.txt '{ s += $NF } END { print s }'
// Rezultat: 15

А това е програмка, която показва броя редове, броя на думите, броя на символите във файл:
awk <tmp.txt '{ w += NF; c += length + 1 } END { print NR, w, c }'

AWK и регулярните изрази

Можем да използваме и регулярни изрази, за да тестваме дали в даден запис във файла съдържа определен текст и тогава да направим нещо с полетата. Примерно, да изкараме само второто поле от list.txt, ако реда започва с 2 или 8:
awk <list.txt '/^8|1/ { print $2 }'
// Rezultat:
// 2
// 4

AWK поддържа POSIX стандарт за регулярните изрази. Можете да използвате почти всичко от стандарта. Ето още един пример:
echo "abcrakijkadef" | awk 'match($0, /c(.*)d/, a) {print a[1]}'
// Rezultat: rakijka

Естествено, че ще набараме ракийката, ако ще и в купа сено да е :)!
Повече за регулярните изрази в AWK можете да прочетете тук: http://www.math.utah.edu/docs/info/gawk_5.html

AWK, като един истински език за програмиране, поддържа и функции и много други неща, но ако искаме да обясним пълните ни възможности, ще ни трябва около една каса биричка и доооста време за писане на удоволствия!

=============================

ЦИКЛИ

if ... else ... fi и малко elif

Кратко обяснение на този цикъл. Ако условието е вярно, тогава изпълни команда1, в противен случай изпълни команда1.
Синтаксис:
if условие
тогава [then] Ако условието е истина
изпълни всички команди до else
в противен случай [else] Ако условието не е истина
изпълни всички конанди до fi
fi

И един пример. Напишете в gedit или друг редактор следния скрипт:
#!/bin/sh
#
# Скрипт, който ще ни покаже дали аргументите са позитивни или негативни
if [ $# -eq 0 ]
then
echo "$0 : Вие трябва да напишете някакво целочислена число"
exit 1
fi
 
 
if test $1 -gt 0
then
echo "$1 е позитивно"
else
echo "$1 е негативно"
fi

В случая използваме четене на аргумент от командния ред. Нека да спомен няколко думи за тези аргументи.
$# - връща броя на аргументите, подадени към изпълнимия скрипт
$0 - връща името на скрипта, който е стартиран
$1, $2 ... - връщат самите аргументи, като $1 е първия, $2 е втория аргумент и т.н.

Най-използваните, според скромното ми мнение, са операндите за сравнение. В общи линии if прави тест за истина по следните критерии:
-lt <
-gt >
-le <=
-ge >=
-eq ==
-ne !=

Повече за тестването и начините на тестване можете да прочетете тук:
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html
С по-горния код показахме и много интелигентен начин за изход от приложение - exit 1. По дефиниция всички успешни команди в linux завършват с изход "0". Когато едно приложение или функция върне резултат различен от "0", тогава изхода от изпълнението е неуспешен. Linux много добре разчита изхода от дадена команда дали е успешен или неуспешен. Това е и основата за piping скриптирането.
Ъ-ъ-ъъъ, а дали не се повтарям...
Запишете скрипта като isnump_n, стартирайте конзолата и направете файла изпълним по следният начин:
chmod 755 isnump_n
или
chmod +x isnump_n

Не забравяйте, че прилагането на команди върху файл изисква да сте в текущата директория на файла (cd ...) или да посочите абсолютния или релативен път до него. Стартирането на скрипта става примерно така:
isnump_n 23

В този цикъл можете да вграждате още if-else-fi вътрешни цикли. Това е за домашна биричка.
По-интересно ще е да разгледаме друга опция на цикъла. Опцията elif. Тя добавя една много лесно постижима мулти-условна система... Лелиии-и-и-и! Споко, много просто е!
Синтаксиса в случая е следния:
if [ условие1 ] then
        ...
изпълнение на някакъв код
elif [ условие2 ] then
        ...
изпълнение на друг код
elif [ условие3 ] then
...
изпълнение на трети код
else
...
        изпълнение на краен код
fi

В примера с разпознаването на числата не бяхме включили варианта "0". Сега, когато разполагаме с elif можем много лесно да го добавим.
#!/bin/sh
#
# Скрипт, който ще ни покаже дали аргументa e позитивeн, негативен или "0"
if [ $# -eq 0 ]
then
echo "$0 : Вие трябва да напишете някакво целочислена число"
exit 1
fi
 
 
if test $1 -gt 0
then
	echo "$1 е позитивно"
elif [ $1 -eq 0 ]
then
	echo "$1 е равно на нула"
else
	echo "$1 е негативно"
fi
 
# Дали ще ползваме test или [ ... ] е все една бира! 
 

Важно е да се запомни, че дали ще ползвате инструкцията test или ъглови скоби е все едно!
За да обогатим знанията си за if нека видим и още един пример. Да напишем програма, която ще изтрие файл, който и посочим:
#!/bin/bash
echo -n "Име на файл за изтриване : "
read myfile
echo -n "Сигурен ли сте ( напишете yes или no ) ? "
read confirmation
confirmation="$(echo ${confirmation} | tr 'A-Z' 'a-z')"
if [ "$confirmation" == "yes" ]; then
   [ -f $myfile ] &&  /bin/rm $myfile || echo "Error - файлът $myfile не съществува в тази папка"
else
   : # не прави нищо
fi

За да изпълните програмата, не забравяйте, че трябва да я направите изпълнима с chmod +x или 755. Иначе няма значение какво име и разширение ще и дадете.
Стига с толкова ифове, че да не станат с цвят :)... е на тоя странен хумор и аз си се чудя, да ме извинявате!

for - Да поциклим с for

For е команда за цикъл, подобен на if. В много случаи двата цикъла са взаимозаменяеми. Но for често е по-удобно за специфични задачки.
Синтаксиса е следния:

for { променлива } in { списък }
            do
                     направи нещо за всеки елемент от списъка
                     докато списъка не свърши
            done

Много прост пример за for:
for i in 1 2 3 4 5
do
  echo "Мара, пичове $i пъти"
done

Това ще изпечата:
Мара, пичове 1 пъти
Мара, пичове 2 пъти
Мара, пичове 3 пъти
Мара, пичове 4 пъти
Мара, пичове 5 пъти

Знам, че е ясно, но все пак леко обяснение. В случая i е променлива, която декларираме в началото на цикъла for. А списъка с елементи е "1 2 3 4 5". Какво би се случило, ако пием една малка ракия и решим да викаме наздраве 3 пъти наздраве на пичовете от бандата:
for i in наздраве наздраве наздраве
do
   echo "Аре пичове $i"
done
#Резултат:
#Аре пичове наздраве
#Аре пичове наздраве
#Аре пичове наздраве 
 

Bash е много либерален, когато се черпавате . Обаче, ако искате всеки път да казвате по една дълга наздравица, дет се вика хайдушка, завършваща с "Ай, на хаирлия да е!!!", тогава ще трябва отделните елементи от списъка да са в кавички.

Обаче for е много удобен за ползване с условия, вместо да го ограничаваме в разни списъци. Какви са тия условия, бе! Като чуя условия и нещо ме стяга за гушата, все едно кандидатствам за кредит в банка!
Чупете гипса! Условията при for са много пивки . Примерно заменяме списъка от 5 елемента, като накараме for сам да си брои, докато ние се почесваме. А са брой, твойта кожа:
for ((i=0; i<10; i++)) do echo 'Аре пичове наздраве!'; done

Естествено това ще изкара десет наздравици! Коледни ! Малко раншко, ам си тря тренировка!
При този тип броене в цикъл фор задължително поставяме условията на броенето в двойни скоби. Това е като да си купите биричка в промоция 3 литра вместо 2... е тогава ще я сложите в двойна найлонка, че да не стане беля! Осоообено, ако сте си взели и едно ливорче от 250г мастичка , за допълване на натюрморта . Абе имаше някаква причина за тия двойни кавички, ам забравих... еххх старост-нерадост.
А! Стих се ! Двойните скоби в bash са подобни на използването на инструмента let. Това е наследен от C тип, който кара bash да изчисли израза в скобите и да го присвои на променлива.
Другото интересно в горния пример е "one-line" или "inline" синтаксиса. Ами нали на конзолата и викат "command line interface". Ако не можем да го жулнем всичкото на екс, то тогава закакъв ми е тоя "command line", нале тей (bash диалект)! Кат ше е лине да е лине!
Има и мезета към това for-броене с условия! Наричат се вложени цикли. Вложените цикли са мега важни, защото позволяват допълнителни условия към основните! Нещо като сложната лихва на банките. Синтаксиса е следния:

for (( условие_едно; условие_две; условие_три ))
do
    for ((подусловие_едно; подусловие_две; подусловие_три ))
    do
        правиш някакви неща с основното условие
        като се съобразяваш с подусловието
   done
done

Пример за подобни сложни гламутории пак с броенето:
for (( i=1; i<=5; i++ ))
do
    for (( j=1; j<=i;  j++ ))
    do
     echo -n "$i"
    done
    echo ""
done
# Резултат:
# 1
# 22
# 333
# 4444
# 55555 
 

Да разгледаме някои интересни приложения на for-цикъла. Както всички останали инструменти и for може да комуникира с останалите инструменти и възможности на Bash.
Например можем да използваме wildcards символите "*", "?", "[...]" за да листнем файловете в директория. На кратко:

* - съответства на всеки символ нула или повече пъти
? - съответства на един символ един път
[a-z] - съответства на всички символи в обхвата. В случая малките букви на латиницата от a до z.

Важно е да се отбележи, че ако няма специални условия for ще манипулира с файловете в текущата или друга директория.

Малко примери:
for i in *; do echo $i; done;
 
# Това ще изпише всички файлове в текущата директория 
 

for i in /dev/l*; do echo $i; done
# Това ще изпише всички файлове в директорията /dev, които започват с буквата l 
 

for i in /dev/[h,s]*; do echo $i; done
# Това ще изпише всички файлове в директорията /dev, които започват с буквите s или h 
 

for i in /dev/???; do echo $i; done
# Това ще изпише всички файлове от /dev, които са с име съставено от 3 символа 
 

for i in /dev/[a-h]??; do echo $i; done
# Това ще изпише всички файлове от /dev, които са с име съставено от 3 символа и името на файла започва с символ в обхвата от a до h 
 

Мисля, че добре разбрахме как да използваме шаблоните wildcards-съвпаденията. Разбира се bash разполага с още по-прецизни и мощни инструменти за търсене на съвпадения, но те са за поети на повечко ноти.

Да видим и малко примери за взаимодействие на for с другия антураж на Bash.
# set е много мощен инструмент, но ние ще разгледаме
# възможността му да разделя променливи на подпроменливи
# като използваме for-цикъл
for n in "aloha dudes" "мара пичове"; do set -- $n; echo "Поздрав: $1" --- "обръщение: $2"; done
# което ще изпринти:
# Поздрав: aloha --- обръщение: dudes
# Поздрав: мара --- обръщение: пичове 
 

Да използваме допълнително броене seq:
for i in $(seq 1 100); do echo -n "file${i}"; done
# Това ще изпечата 100 думи: file1 file2 file3 file4 file5... 
 

Можем да го използваме за да създадем 100 празни файла с имена в определена последователност:
for i in $(seq 1 100); do touch file${i} 2>&1; done

Ако сте се объркали и сте създали горните 100 файла :), можете да използвате "зелените карти" за да почистите:
rm file?

Естествено можем да си използваме и инструмента за списъци, което често е много по-лесно, особено за махмурлии:
for i in {a..d}; do echo $i; done

Надявам се да разбрахте тая гад for! Ако не разбрахте, значи ви е малко пийньето!!! А наздраве!

Следва продължение ...pipeline, function, стартиране на команди в поток и условия, йероглифите в bash...
Да се оправят новите редове в някои кодове, сърварая изяжда наклонената черта и при изпълнение на кода се получават странни резултати.

редактиран от phrozencrew на 16.11.09 22:11
редактиран от phrozencrew на 17.11.09 21:33
редактиран от phrozencrew на 17.11.09 21:36
редактиран от phrozencrew на 18.11.09 19:23
редактиран от phrozencrew на 19.11.09 19:43
редактиран от phrozencrew на 20.11.09 21:40
редактиран от phrozencrew на 01.12.09 10:12
редактиран от phrozencrew на 04.05.10 21:15
редактиран от phrozencrew на 08.12.10 20:50
редактиран от phrozencrew на 09.12.10 19:51
редактиран от phrozencrew на 08.09.11 18:59
редактиран от phrozencrew на 15.07.12 11:59
dhtj
Пон, 16.11.09, 22:32
абе я почвай да се занимаваш със администриране, бая парици ще вземаш, остави ги тея хладилници да си ги праят германците
поклон пред тебе
galkamalka
Пон, 16.11.09, 22:50
Еййй това ще стане книга, а? Супер, дано нямаш нищо против да следя темата с интерес
Така и така подхвана "|" ...това са условни оператори определящи дали да се извърши следващата команда, когато е двоен "||" втората команда ще бъде изпълнена ако първата е грешна:
команда1 || команда2

Когато има двоен "&&" ще бъдат изпълнени навързаните команди без съобщение при евентуална грешка:
команда1 && команда2 && команда3

А ако следващите команди са в скоби или разделени със запетая ще бъдат изпълнени при вярна първа:
команда1 && (команда2; команда3)
# това е същото
команда1 && команда2, команда3

А за кавичките колкоо знааам.....

kookki
Пон, 16.11.09, 23:06
6+
Не мога да се включа потемата но я чета с интерес. Радвам се че споделяте знания
phrozencrew
Вто, 17.11.09, 00:02
Благодаря за подкрепата! Разбира се ще продължим с тутора, като и междувременно ще си коментираме разни неща.
galkamalka, естествено, че ще стигнем и до операторите за сравнение "||" и "&&", но те се намират някъде далеч в бъдещето, където е и test. А и с тях не се работи толкова лесно. Не можеш директно да ги присвоиш към променлива, а и двойните квадратни (големи) скоби си искат разясняване. Лека-полека , дай да не пришпорваме и да плашим народа!

Може би ще е добре да се кажат още няколко дъми за присвояването на променливи от изпълнението на команда, или пък да споменем за конкатенацията на променливите в bash, макар, че определен вид конкатенация с ++ важи само за версии след 3-ката. Ще обмисля, кое е добре и не е много плашещо да се вкара на този етап. Утре викам да продължим по-сериозно с printf, и да допълним малко инфо за echo.

insecteater
Вто, 17.11.09, 10:51
На български е по-удобно наистина. Поздравления за ентусиазма и труда. (и хумора :P)
редактиран от insecteater на 17.11.09 11:02
phrozencrew
Вто, 17.11.09, 21:40
Благодаря Ганчо! Добавих още малко инфо към туториала (echo и printf). Ако имаш възможност добави някоя идея или критика. Сигурен съм, че добре познаваш конзолата, особено след сблъсъка с Gentoo !
phrozencrew
Чет, 19.11.09, 20:06
Добавих още малко инфо. За инструментите от coreutils трябва да се поизпише доста, защото те са основата на bash-скриптовете. Ако искате да коригирам нещо или да добавя още информация и примери - моля споделете :).
dreamskill
Чет, 19.11.09, 21:00
Поздравления, Нед! Друг отличен урок, както "Как да създадем Web сайт само с Notepad++"!

< 1 2 >

Коментар

за нас | за разработчици | за реклама | станете автори | in english  © 1998-2019   Experta Ltd.