ПРА: Linux скриптовање - белешке са вежби
Садржаји су углавном преузети из књиге TLCL, биће назначено о којој се области ради. Биће излистани одабрани садржаји са примерима ради лакше навигације.
Манипулација називима датотека
Област 4 - Wildcards && Област 7 - Pathname expansion
*- мења било који (низ) карактера,?- мења било који карактер,[скуп]- мења било који карактер који припада задатом скупу, док скуп може бити кориснички дефинисан, или постојећи, односно предефинисан,[!скуп]- мења било који карактер који не припада скупу,[[:класа:]]- мења било који карактер који припада наведеној класи, а примери за класе су:[:alnum:]- мења било који алфанумерички карактер (слова или бројеви),[:alpha:]- мења било које слово,[:digit:]- мења било коју цифру/број,[:lower:]- мења било које мало слово,[:upper:]- мења било које велико слово.
Примери
echo * # излистава све датотеке које се налазе у тренутном радном директоријуму
echo [abc]* # излистава све датотеке које се налазе у тренутном радном директоријуму и чији назив почиње или малим словом "a", или "b", или "c"
echo primer?.txt # излистава све датотеке које се налазе у тренутном радном директоријуму и које у свом називу имају реч primer праћену тачно једним карактером (рецимо број, нумерација; али може бити било који други карактер), а потом и екстензију (суфикс) .txt
echo primer[0-9].txt # излистава све датотеке које се налазе у тренутном радном директоријуму и које у свом називу имају реч primer праћену тачно једним бројем, а потом и суфиксом .txt
echo [[:upper:]]* # излистава све датотеке које се налазе у тренутном радном директоријуму и чији назив почиње великим словом
Област 7 - Brace expansion
На место означено витичастим заградама убацити више различитих вредности, дефинисаних задатим скупом/опсегом.
Пример
mkdir -p proba/godina_{1926..2026}/mesec_{jan,feb,mar}/nedelja_{1..4}
Проширење (eкспанзија) специјалним карактером $
Област 7 - Arithmetic expansion
$((израз))- евалуира и враћа вредност прослеђеног израза, подржане су основне математичке операције:+- сабирање,-- одузимање,*- множење,/- дељење,%- остатак при дељењу,**- степеновање.
Пример
echo $(($((5**2)) * 3)) # 75
Област 7 - Parameter expansion
$VAR- враћа вредност променљиве под називомVAR
Пример
echo $USER # враћа ваше корисничко име
Област 7 - Command substitution
$(command)- враћа резултат извршења прослеђене наредбеcommand
Пример
CURRENT_DIR=$(pwd) # унутар променљиве је смештена путања до директоријума у ком се тренутно налази корисник
Избегавање (escape) специјалних карактера
Област 7 - Quoting
До сада је виђен велики број карактера који имају посебно значење зависно од случаја употребе. Некада је неопходно ипак занемарити та специјална значењa. Такозвано избегавање (escape) се може постићи на више начина:
- коришћењем
\- назначава да карактер који следи не треба посматрати као специјалан, - коришћењем
" "- садржај унутар двоструких наводника се третира као регуларан стринг, односно занемарују се специјални карактери; изузеци су\,$, и`, - коришћењем
' '- садржај унутар једноструких наводника се третира као регуларан стринг, односно занемарују се сви специјални карактери.
Примери
mkdir Moj Direktorijum
mkdir Moj\ Direktorijum
mkdir "Moj Direktorijum"
mkdir 'Moj Direktorijum'
echo text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER"
echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER'
Регуларни изрази
Област 19 - Regular Expressions
Превасходно се користе за манипулациjу текстуалног садржаjа, и интегрисани су у наредбу grep, коjа се користи за претрагу садржаjа датотека. Могуће jе регуларне изразе користити и за претрагу путања до датотека или директоријума, у комбинациjи са функциjом find.
.- мења било који карактер,^и$- форсирају да се уклапање у образац дефинисан изразом налази на почетку, односно крају линије, респективно,[скуп]- мења било који карактер који припада задатом скупу, скуп може бити кориснички дефинисан, или постојећи, односно предефинисан,[^скуп]- мења било који карактер који не припада скупу.
Примери
grep -i '^..j.r$' /usr/share/dict/words # за хипотетичке укрштенице, тражи речи садржане у речнику, такве да имају 5 слова, од којих је познато треће слово "j", и последње слово "r".
mkdir -p vezbanje/tes{t,T}
ls ./vezbanje/ > proba.txt
grep '[A-Z]$' proba.txt
find ./vezbanje/ -type d -regex '.*[A-Z]$'
# ово тражи директоријуме чији се назив завршава великим словом
# уочити да је за позив наредбе find неопходно експлицитно нагласити да се употребљава регуларни израз
# уједно је код find наредбе неопходно уклопити цео стринг у регуларни израз, а не само произвољни подстринг
# уочити да наредба find враћа читаву путању до жељене датотеке
Постоји више различитих дијалеката регуларних израза, односно начина на који се “чита” написани шаблон регуларног израза. Наредба grep подразумевано користи Basic Regular Expressions (BRE) дијалекат. Међутим, постоји додатан сет специјалних карактера за регуларне изразе који је могуће користити у оквиру Extended Regular Expressions (ERE) дијалекта. И BRE и ERE су усклађени са POSIX стандардом. Да би наредба grep користила дијалекат ERE потребно је додати заставицу (флег) -E (или алтернативно позвати функцију egrep). Наредба find за претрагу датотечног система подразумевано користи дијалекат Emacs стила за регуларне изразе који није усклађен са POSIX стандардом као што су BRE и ERE дијалекти. Да би и наредба find користила ERE дијалекат, потребно је специфицирати опцију -regextype posix-extended (заједно са -regex "pattern"). Додатни специјали карактери доступни у оквиру Extended Regular Expressions (ERE) дијалекта су:
|- алтернација између више регуларних израза; слично као и[ ], а тражи се поклапање са једном од жељених опција, али се не ради о сингуларном карактеру, већ о читавом (под)стрингу,?- означава да је претходни карактер опциони, дакле може се појавити 0 или 1 пут,*- поново, означава да је претходни карактер опциони, али може се појавити 0 или више пута,+- означава претходни карактер као обавезни, односно може се појавити 1 или више пута,{#}- користи се да се специфицира егзактан број појављивања претходног карактера:{n}- претходни карактер се појављује тачно n пута,{n,m}- претходни карактер се појављује најмање n, а не више од m пута,{n,}- претходни карактер се појављује n или више пута,{,m}- претходни карактер се појављује највише m пута.
Примери
echo "(555) 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
echo "555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
echo "5555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
# заграде код "позивног" броја су опционе, он се састоји из тачно 3 цифре, што је праћено са још 3 цифре, -, и на крају још 4 цифре
echo "AAA" | grep -E 'AAA|BBB'
echo "BBB" | grep -E 'AAA|BBB'
echo "CCC" | grep -E 'AAA|BBB'
mkdir -p vezbanje/test_{1..6}
ls ./vezbanje/ > proba.txt
grep -E '(test_1|test_3|test_5)' proba.txt
Скриптовање
Гранање
Област 27 - Branching with if
Синтакса за употребу гранања (псеудокод):
if услов_1; then
први
блок
наредби
elif услов_2; then
други
блок
наредби
else
последњи
блок
наредби
fi # не заборавити ово за затварање!
Наведени услови се евалуирају конверзијом у True или False, тако што се имплицитно врши позив наредбе test.
test expression
#или
[ expression ]
# конкретно пример провере једнакости вредности променљиве X и целобројне вредности 5
if [ "$x" -eq 5 ]; then ...
Тестови који се извршавају над датотекама:
-e: проверава да ли датотека/директоријум постоји,-d: проверава да ли датотека/директоријум постоји И да ли се ради о директоријуму ,-f: проверава да ли датотека/директоријум постоји И да ли се ради о датотеци (regular file),-r,-w,-x: проверава да ли датотека/директоријум постоји И да ли корисник има привилегију за читање, писање, извршавање, респективно;-s: проверава да ли датотека постоји И да ли има неки садржај (да ли јој је величина већа од 0). Не користи се и за проверу постојања садржаја директоријума.
Пример
#!/bin/bash
# test-file: Evaluate the status of a file
FILE=~/.bashrc
if [ -e "$FILE" ]; then
if [ -f "$FILE" ]; then
echo "$FILE is a regular file."
fi
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
fi
if [ -r "$FILE" ]; then
echo "$FILE is readable."
fi
if [ -w "$FILE" ]; then
echo "$FILE is writable."
fi
if [ -x "$FILE" ]; then
echo "$FILE is executable/searchable."
fi
else
echo "$FILE does not exist"
exit 1
fi
exit
Тестови који се извршавају над стринговима:
-n string- проверава да ли стринг није празан (дужина му је већа од 0),-z string- проверава да ли је стринг празан (дужина му је 0),s1 == s2- проверава једнакост два стринга,s1 != s2- проверава неједнакост два стринга.
Пример
#!/bin/bash
# test-string: evaluate the value of a string
ANSWER=maybe
if [ -z "$ANSWER" ]; then
echo "There is no answer." >&2
exit 1
fi
if [ "$ANSWER" == "yes" ]; then
echo "The answer is YES."
elif [ "$ANSWER" == "no" ]; then
echo "The answer is NO."
elif [ "$ANSWER" == "maybe" ]; then
echo "The answer is MAYBE."
else
echo "The answer is UNKNOWN."
fi
Тестови који се извршавају над целобројним вредностима:
int1 -eq int2- проверава да ли су два цела броја једнака,int1 -ne int2- проверава неједнакост два цела броја,int1 -le int2- проверава да ли је први цео број мањи или једнак другом,int1 -lt int2- проверава да ли је први број мањи од другог,int1 -ge int2- проверава да ли је први цео број већи или једнак другом,int1 -gt int2- проверава да ли је први број већи од другог.
Пример
#!/bin/bash
# test-integer: evaluate the value of an integer.
INT=-5
if [ -z "$INT" ]; then
echo "INT is empty." >&2
exit 1
fi
if [ "$INT" -eq 0 ]; then
echo "INT is zero."
else
if [ "$INT" -lt 0 ]; then
echo "INT is negative."
else
echo "INT is positive."
fi
if [ $((INT % 2)) -eq 0 ]; then
echo "INT is even."
else
echo "INT is odd."
fi
fi
Постоје две модификације наредбе test, једна за рад конкретно са целобројним вредностима, а друга која дозвољава и проверу стрингова употребом регуларних израза:
(( expression )) # за рад са бројевима
#и
[[ expression ]] # проширење које подржава регуларне изразе
Пример
#!/bin/bash
# test-integer2a: evaluate the value of an integer.
INT=-5
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then # - као предзнак је опциони, и праћен је низом цифара
if ((INT == 0)); then # уочити да се вредности променљивих унутар (()) директно евалуирају без употребе $
echo "INT is zero."
else
if ((INT < 0)); then
echo "INT is negative."
else
echo "INT is positive."
fi
if (( ((INT % 2)) == 0)); then
echo "INT is even."
else
echo "INT is odd."
fi
fi
else
echo "INT is not an integer." >&2
exit 1
fi
Могуће је комбиновати резултате евалуације услова коришћењем следећих оператора:
AND- логичко И, унутарtest ([ ])наредбе дефинише се заставицом-a, док се унутар проширења[[ ]]и(( ))означава са&&,OR- логичко ИЛИ, унутарtest ([ ])наредбе дефинише се заставицом-o, док се унутар проширења[[ ]]и(( ))означава са||,NOT- логичко НЕ, означава се са!.
Пример
#!/bin/bash
# test-integer3: determine if an integer is within a
# specified range of values.
MIN_VAL=1
MAX_VAL=100
INT=50
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
if [[ "$INT" -ge "$MIN_VAL" && "$INT" -le "$MAX_VAL" ]]; then
# if [ "$INT" -ge "$MIN_VAL" -a "$INT" -le "$MAX_VAL" ]; then # алтернативно
# if (( ((INT >= MIN_VAL)) && ((INT <= MAX_VAL)) )); then # алтернативно
echo "$INT is within $MIN_VAL to $MAX_VAL."
else
echo "$INT is out of range."
fi
else
echo "INT is not an integer." >&2
exit 1
fi
Уједно се у оквиру области 27 налази секција о операторима контроле тока (Flow Control) - други начин за гранање. Конкретно, за овај вид гранања се користе оператори AND и OR:
command1 && command2- извршава се наредбаcommand1; а потом се дешава извршавањеcommand2акко (ако и само ако) је извршавањеcommand1било успешно,command1 || command2- извршава се наредбаcommand1; а потом се дешава извршавањеcommand2акко (ако и само ако) је извршавањеcommand1било неуспешно.
Могуће је произвољно много наредби спрегнути помоћу поменутих команди.
Примери
mkdir temp && cd temp # идеја је да се направи нови директоријум, а потом и да се у њега пређе
# прво се извршава команда за прављење новог директоријума
# прелазак у нови директоријум ће се десити акко је успешно направљен поменути директоријум
[[ -d temp ]] || mkdir temp # идеја је проверити да ли већ постоји директоријум који је потребно направити
# прво се извршава провера
# прављење директоријума ће се десити акко се провера да ли он већ постоји евалуира као False
[[ -d $NEW_DIR ]] && echo $NEW_DIR already exists, aborting && exit
mkdir $NEW_DIR
# прво се извршава провера постојања директоријума са истим називом као онај који треба направити
# уколико такав директоријум НЕ постоји, даље наведене наредбе (у десно) се не извршавају, односно прелази се на нови ред
# уколико такав директоријум заиста постоји, извршава се следећа наредба (еcho)
# уколико се позив echo наредбе успешно изврши, извршава се и наредба exit
Switch - case
Конструкција switch-case подразумева тражење поклапања вредности неке променљиве са једним од понуђених калупа (образаца). Користи се сет специјалних карактера описан у првом поглављу. Синтакса је следећег облика (псеудокод):
case "@реч" in
образац_1) први
блок
наредби
;; #& опционо
образац_2) други
блок
наредби
;; #& опционо
.
.
.
образац_N) последњи
блок
наредби
;; #& опционо
*) echo "Лош унос!"
exit 1
esac # затварање case-а!
- Идеја је да се вредност променљиве
речуклопи у један од дефинисаних образаца, и онда се изврши одговарајући блок наредби. - Подразумевано се провера зауставља при првом успешном поклапању.
- Могуће је навести структуру да настави даље провере употребом специјалног карактера
&(за случај да је очекивано, и потребно да се вредност променљиверечуклапа у више од једног обрасца). - Добра је пракса поставити за последњи у низу образаца
*)ради хватања изузетака, односно потенцијалних грешака, или уколико се жели навести подразумевано понашање за случај када ниједно од претходних поређења није задовољено.
Примери
#!/bin/bash
rec="нека_реч"
case "$rec" in
[[:alpha:]])
echo "Реч се састоји из тачно једног словног карактера." ;;
[ABC][0-9])
echo "Реч се састоји из A или B или C карактера, праћено цифром." ;;
???)
echo "Реч се састоји од 3 карактера." ;;
*.txt)
echo "Реч се завршава са '.txt'." ;;
*)
echo "Реч је нешто друго." ;;
esac
#!/bin/bash
karakter="A"
case "$karakter" in
[[:upper:]])
echo "'$karakter' је велико слово." ;;&
[[:lower:]])
echo "'$karakter' је мало слово." ;;&
[[:alpha:]])
echo "'$karakter' је слово." ;;&
[[:digit:]])
echo "'$karakter' је цифра." ;;&
[[:space:]])
echo "'$karakter' је space." ;;&
esac
Кориснички унос
Два приступа - тражење корисничког уноса унутар саме скрипте, или употреба позиционих параметара дефинисаних при позиву скрипте (Област 32).
- Функција read, пандан функцији input() у Пајтону:
read unos # у променљиву unos се уписује вредност са стандардног улаза - Позициони параметри се дефинишу при позиву скрипте:
./skripta.sh parametar1 parametar2 parametarNПриступ и манипулација параметрима унутар скрипте се извршава помоћу пар специјалних променљивих/команди:
$0- резервисан за назив скрипте која је покренута; на нулти позициони параметар не утиче позив shift наредбе,$(1-9)-$праћен редним бројем (позицијом) параметра приступа вредности прослеђених параметара при позиву скрипте (1,2,…,9). За приступ параметру на позицији већој од 9 користити${n}, нпр.${100},$#- број прослеђених позиционих параметара при позиву скрипте (не укључујући 0-ти, резервисани параметар),$@- акумулирање свих прослеђених параметара у један низ,shift- помера све параметре, односно мења им позицију за 1 (иницијално други параметар постаје први, иницијално трећи параметар постаје други, …).
Пример
#!/bin/bash
# pp.sh: script to view command line parameters
echo "
Number of arguments: $#
\$0 = $0
\$1 = $1
\$2 = $2
\$3 = $3
\$4 = $4
\$5 = $5
\$6 = $6
\$7 = $7
\$8 = $8
\$9 = $9
"
shift
echo "
After shift
Number of arguments: $#
\$0 = $0
\$1 = $1
\$2 = $2
\$3 = $3
\$4 = $4
\$5 = $5
\$6 = $6
\$7 = $7
\$8 = $8
\$9 = $9
"
./pp.sh a b c d
Number of arguments: 4
$0 = ./pp.sh
$1 = a
$2 = b
$3 = c
$4 = d
$5 =
$6 =
$7 =
$8 =
$9 =
After shift
Number of arguments: 3
$0 = ./pp.sh
$1 = b
$2 = c
$3 = d
$4 =
$5 =
$6 =
$7 =
$8 =
$9 =
For петља
Област 33 - Looping with for
Синтакса за употребу for петље:
for i in iterable; do
#for i in $@: do # рецимо
#for i; do # исто као ово изнад, ако се не наведе експлицитно по чему се итерира, подразумевају се позициони параметри
блок
наредби
у петљи
done # не заборавити ово за затварање!
# или, aко сте користили већ C
for (( i=0; i<5; i=i+1 )); do
echo $i # нпр само прост бројач
done