VŠB - Technická univerzita Ostrava Fakulta elektrotechniky a informatiky
Technologie počítačových sítí Stručná systematická příručka s příklady k použití TCL na Cisco IOS
2008
Pavel NEJEDLÝ Jan KOCMÁNEK
Obsah Úvodní seznámení ...................................................................................................................... 3 Poznámky, komentáře ................................................................................................................ 3 Proměnné.................................................................................................................................... 3 Vstup a výstup............................................................................................................................ 4 Matematické operace.................................................................................................................. 4 Funkce ........................................................................................................................................ 5 Podmíněné příkazy..................................................................................................................... 6 Iterační příkazy (cykly) .............................................................................................................. 8 Strukturované datové typy ....................................................................................................... 10 Práce s řetězci........................................................................................................................... 11 Poznámky k CISCO implementaci .......................................................................................... 14 Spouštění Tcl příkazů............................................................................................................... 15 Použité zdroje........................................................................................................................... 15 Příklady .................................................................................................................................... 16
2
Úvodní seznámení Jednotlivé příkazy jsou v Tcl od sebe odděleny koncem řádku (odřádkováním) nebo středníkem. Pokud je na řádku uveden pouze jeden příkaz, nemusí se za ním středník psát. Příkaz je složen z jednoho nebo více slov, která jsou od sebe oddělena mezerou nebo tabelátorem. První slovo je chápáno jako název příkazu (funkce, procedury), další slova jsou chápána jako parametry. Pokud chceme použít jako parametr řetězec obsahující mezery použijeme uvozovky, jinak se používat nemusí všechny parametry jsou chápany jako řetězec. puts "Hello world"
vypíše na výstup: Hello world
Poznámky, komentáře Poznámky začínají znakem #(hash). # toto je poznámka k příkazu nebo k funkci
Vzhledem k tomu, že je začátek poznámky (#) považován za příkaz, musí poznámka buď začínat na novém řádku, nebo musí být (pokud je na stejném řádku s příkazem) od předchozího příkazu oddělena středníkem. puts "Hello world"; # vypise hello world na vystup
Proměnné Každá použitá proměnná musí být před svým prvním použitím inicializována. Inicializace se provádí příkazem set, za nímž se uvede jméno proměnné a její hodnota (ta může být vyjádřena buď konstantou, nebo příkazem/výrazem, který se vyhodnotí). Hodnoty jsou považovány za řetězce, žádný jiný datový typ Tcl nezná. Příkazem set nelze nastavit více proměnných najednou, ale pouze jen jednu. set hello "Hello world" set num 128
Pokud se příkaz set zadá pouze s názvem proměnné, vrátí se její hodnota. O zrušení proměnné se stará příkaz unset, kterému se předá název proměnné. Po provedení tohoto příkazu je proměnná uvolněna z paměti, což je, zvláště v případě, kdy se používají rozsáhlá asociativní pole či seznamy, mnohdy velmi vhodné. unset hello unset num
Pokud potřebujeme získat hodnotu proměnné, musí se před její jméno vložit znak $(dolar), který způsobí substituci jména proměnné za její hodnotu. Použité znaky $ [] "" {} \
Význam znaků substituce proměnných - náhrada jména proměnné její hodnotou vyhodnocení příkazu - příkaz v závorkách se vyhodnotí nejdříve potlačuje zpracování mezer jako oddělovačů příkazů či jejich argumentů stejné jako uvozovky, s tím rozdílem, že se všechny substituce uvnitř závorek zakazují ruší zvláštní význam následujícího znaku
3
Vstup a výstup Obecný příkaz pro zápis na zařízení popsané descriptorem je puts, descriptor může být výstup na terminál, socket. Pokud descriptor neuvedeme použije se výstup na terminál. puts descriptor [proměnná]
Obecný příkaz pro čtení ze zařízení pomocí jeho descriptoru je gets. gets descriptor [proměnná]
Výpis na terminál (přesněji řečeno na standardní výstup). puts "Hello world" puts stdout "Hello world" set vyraz [expr 1+1] puts $vyraz puts [expr 1+1]
Čtení z terminálu (ze standardního vstupu). gets stdin hodnota puts $hodnota
Při použití proměnné, která není inicializována jí příkaz gets rovnou inicializuje.
Matematické operace Jazyk Tcl neobsahuje žádné speciální konstrukce pro zápis matematických operací, místo toho má k dispozici příkaz (funkci) expr, kterému je možné předložit zápis matematického výrazu, ten se vyhodnotí a funkce vrátí výsledek daného výrazu. expr expr expr expr
1 + 2 10.0 / 5 1 << 10 $a + $b
Jak je z předchozího příkladu patrné, je možné v příkazu expr používat jak číselné konstanty (tyto mohou být celočíselné i reálné), tak i proměnné. Argumenty příkazu expr nemusí být odděleny mezerou (což je tak trochu výjimka) a proto lze psát: expr expr expr expr
1+2 10.0/5 1<<10 $a+$b
Příkaz expr lze samozřejmě použít i společně s dalšími příkazy, hojně se zde využívá hranatých závorek ovlivňujících prioritu provádění jednotlivých příkazů. set set set set
a b c c
[expr 1+2] 20 "$a + $b se rovná [expr $a + $b]" {$a + $b se rovná [expr $a + $b]}; # zde nedojde k substituci
4
Operace Význam Matematické operace + unární plus unární mínus + součet (dále se již jedná o binární operace) rozdíl * součin / podíl % zbytek po dělení Logické a bitově orientované operace << bitový posun doleva >> bitový posun doprava ~ negace bit po bitu ! logická negace & bitový operátor AND | bitový operátor OR ^ bitový operátor XOR && logický součin (a zároveň) || logický součet (nebo) ?: ternární podmíněný výraz < menší než > větší než <= menší nebo rovno >= větší nebo rovno == rovnost != nerovnost
přehled matematických operací a logických operátorů
Funkce Pro vytvoření nové funkce se používá příkaz proc, za nímž se uvede název nové funkce, její parametry (ty se uvnitř funkce chovají jako proměnné) a tělo funkce (tj. jednotlivé příkazy, ze kterých se funkce skládá). Funkce může být při svém zavolání kdykoli přerušena příkazem return, který může vracet nějakou hodnotu. Pokud se funkce ukončí jiným příkazem než return, vrátí se hodnota posledně prováděného příkazu (návratovou hodnotu je samozřejmě možné ignorovat). proc hello {} { puts "Hello world" }
Příklad jednoduché funkce bez parametrů. Všimněte si zápisu těla funkce do složených závorek. To je v tomto případě nutné, protože jinak by se tělo funkce vyhodnotilo již při jejím vytvoření. Dále je nutné, aby druhá otevírací složená závorka byla na stejném řádku jako příkaz proc - všechny příkazy v Tcl jsou řádkově orientované. Příkazy uvnitř těla funkce se již mohou formátovat libovolně, protože uvnitř složených závorek je povoleno používat znak konce řádku.
5
Příklad funkce se dvěma parametry vracející výsledek: proc secti {a b} { return [expr $a+$b] }
Podmíněné příkazy
if-then-else
if podmínka {tělo_podmínky}
Tcl je poměrně variabilní a podporuje i další způsoby vytváření podmínek. První je ve své podstatě pouze podpůrnou variantou, uvedením slova then přímo za výraz specifikující podmínku (pro zajištění snadného přechodu z jiných programovacích jazyků např. basicu). if {podmínka} then {tělo_podmínky}
Podmínka může být též uvnitř složených závorek {}, ale má to význam pokud bude podmíněný výraz obsahovat mezery. Další variantou je přidání druhé větve příkazů, které se vykonají v případě, že podmínka není splněna, tj. vyhodnotí se na logickou hodnotu „false“. I zde je možné (nikoli však nutné) použít slovo then, slovo else uvozující druhou větev také nemusí být použito. if if if if
podmínka podmínka podmínka podmínka
{tělo_podmínky} {tělo_druhé_větve} {tělo_podmínky} else {tělo_druhé_větve} then {tělo_podmínky} {tělo_druhé_větve} then {tělo_druhé_větve} else {tělo_druhé_větve}
Vzhledem k tomu, že se v reálných problémech nepoužívají pouze jednoduché podmíněné výrazy, ale složitější struktury, obsahuje Tcl rozšíření pro zápis více podmíněných výrazů a větví v jednom bloku if. Jedná se o vícenásobně použité slovo elseif, za nímž vždy následuje vyhodnocovaný výraz a tělo (blok příkazů), které se provede v případě, že je výraz vyhodnocen jako pravdivý. if podmínka {tělo1} elseif podmínka2 {tělo2} tělo_else if podmínka then {tělo1} elseif podmínka2 then {tělo2} else {tělo_else}
Na tomto místě je třeba upozornit na fakt, že slovo elseif je nutné uvádět, nelze s ním tedy zacházet tak liberálně jako se slovy then a else. Při zápisu podmíněného příkazu na více řádků je zapotřebí zaručit, aby se začátek případné větve else nacházel na stejném řádku, kde je uzavírací závorka větve then. Je to z toho důvodu, že Tcl celý skript zpracovává po jednotlivých řádcích a v případě, že by řádek začínal přímo slovem else, považoval by ho interpreter za začátek dalšího příkazu. if {výraz} { tělo_podmínky } else { tělo_druhé_větve }
Stejné pravidlo platí pro zápis dvou větví bez slova else: if {výraz} { tělo_podmínky } { tělo_druhé_větve }
6
Nyní se podíváme na pár příkladů zápisu if-then-else. set h 5 if $h<10 {puts "mensi nez 10"} if $h<10 then {puts "mensi nez 10"} if {$h < 5} {puts "mensi nez 5"} {puts "neni mensi nez 5"} if $h<5 {puts "mensi nez 5"} else {puts "neni mensi nez 5"} if $h<3 {puts mensi} elseif $h==3 {puts rovno} {puts vetsi} if $h<3 {puts mensi} elseif $h==3 {puts rovno} else {puts vetsi} if {$h<5} { puts "mensi nez 5" } else { puts "neni mensi nez 5" } if {$h<3} { puts mensi } elseif {$h==3} { puts rovno } else { puts vetsi }
Switch Vzhledem k tomu, že všechny hodnoty jsou v Tcl reprezentovány pomocí řetězců, porovnávají se v příkazu switch právě řetězce, přičemž je možné specifikovat porovnávání na základě regulárních výrazů, což celý příkaz switch posouvá na mnohem vyšší úroveň použitelnosti. switch řetězec vzor1 větev1 vzor2 větev2 ... default větev_n
Pokud použijeme místo příkazů větve pomlčku (-), znamená to, že se provede tělo dalšího vzoru. set test router switch $test router {puts router} switch {puts switch} default {puts unknown}
Testuje jestli se obsah proměnné test shoduje s nějakým vzorem (router, switch), pokud ano vypíšeme název vzoru, pokud test obsahuje něco jiného vypíše se „unknown“. set test router switch $test { router {puts router} switch {puts switch} default {puts unknown} }
Přehlednější zápis na více řádků. Jednotlivé větve se nemusí ukončovat žádným příkazem typu break - vždy se provede maximálně jedna větev. Větev označená slovem default je přitom brána jako implicitní, tj. pokud není splněna žádná z podmínek, provede se právě tato část programu. Podmínkami příkazu switch je obecně regulární příkaz, který slouží k porovnání libovolného řetězce se zadanými vzory. Kromě toho je možné příkazu switch zadat několik voleb, kterými se ovlivňuje způsob porovnání řetězců. Jedná se o následující volby:
7
Volba -exact -glob -regexp
Význam volby exaktní porovnávání řetězce se vzorem (implicitní nastavení) porovnávání na základě jednodušší formy regulárního výrazu (jako v shellu) porovnávání na základě rozšířené formy regulárního výrazu (jako ve Vimu)
Volby příkazu switch
Iterační příkazy (cykly) while Základní a zcela univerzální smyčkou je while. while podmínka telo_smyčky
Před prvním provedením smyčky se vyhodnocuje podmínka stejným způsobem jako u podmíněného příkazu if. Pokud je výsledkem vyhodnocení podmínky logická hodnota "true", vykoná se jedna iterace a řízení programu se vrátí na začátek smyčky, tj. na test podmínky. Pokud se je výsledkem vyhodnocení podmínky logická hodnota "false", pokračuje běh programu příkazem uvedeným za smyčkou. set i 1 while {$i<10} { puts $i set i [expr $i+1] }
příklad jednoduché smyčky, jejíž běh je řízen proměnnou i, kde se v každém kroku vypíše její hodnota. Smyčka se provede celkem devětkrát Jak je z předchozího příkladu patrné, pro zvýšení hodnoty proměnné i o jedničku se používá celkem složitého zápisu pomocí expr. V Tcl existuje příkaz incr, který zvýší či sníží hodnotu proměnné o zadané číslo. Pokud není žádné číslo v příkazu incr zadáno, zvýší se implicitně hodnota proměnné o jedničku. set i 1 while {$i<10} { puts $i incr i }
Zpětné počítání je jednoduché, postačí specifikovat záporný krok set i 10 while {$i} { puts $i incr i -1 }
vypisuje čísla od deseti do jedné
8
for Kromě smyčky while je možné použít i "počítanou" smyčku for. for start test iterační_příkaz tělo_smyčky for {set i 1} {$i<10} {incr i} { puts $i }
příklad jednoduché smyčky z minulého příkladu zapsané pomocí for, v každém kroku vypisuje hodnotu proměnné i, od jedné do devíti. V obou uvedených smyčkách je možné použít příkazy break a continue. Příkazem break se může smyčka v libovolném místě předčasně ukončit. Příkaz continue způsobí skok na začátek smyčky. foreach Pro průchod seznamem (viz. Strukturované datové typy) je samozřejmě možné použít smyčky while či for - stačí využít funkce llength a lindex. To však není příliš efektivní ani přehledné, proto byla Tcl obsahuje smyčku foreach, která se používá právě při práci se seznamy. foreach proměnná seznam tělo_smyčky
Podobně jako u smyčky for se i zde používá řídicí proměnná. Tato proměnná však nenabývá číselných hodnot, ale jsou do ní postupně dosazovány jednotlivé prvky seznamu. foreach i {jedna dve tri ctyri} { puts $i }
postupně vypíše slova jedna, dve, tri, ctyri Ve složitějších případech je možné použít i seznam názvů proměnných, do kterých se při běhu smyčky budou postupně dosazovat sousední prvky. foreach {i j} {1 2 3 4 5 6} { puts "i= $i" puts "j= $j" }
postupně vypíše i= 1, j= 2.. i= 3, j= 4.. i= 5, j= 6 Poslední modifikací smyčky foreach je specifikace jedné či více proměnných, kde každá proměnná bude použita pro svůj vlastní seznam. foreach i {1 2 3} j {4 5 6} { puts "i= $i" puts "j= $j" }
výpíše postupně i= 1, j= 4...pokud by jeden seznam byl kratší než druhý bude výpisem prázdná hodnota
9
Strukturované datové typy Programovací jazyk Tcl umožňuje základní práci pouze se skalárními hodnotami. Vzhledem ke značné rozšiřitelnosti jazyka však není problémem pracovat i se strukturovanými datovými typy. Mezi tyto datové typy patří zejména asociativní pole a seznamy. Asociativní pole Tcl nepoužívá klasická pole indexovaná číselnými hodnotami, ale asociativní pole, kde je klíčem obecně libovolný řetězec. set pole(0) 100 set pole(1) 150 set pole(9) "hello world" puts $pole(0) puts $pole(1) puts $pole(9)
Jak bylo zmíněno v předchozím odstavci, lze jako klíč použít libovolný řetězec, což je ukázáno na dalším příkladu s typickým využitím asociativních polí pro tvorbu velmi jednoduchého slovníku. set slovnik(pocitac) computer set slovnik(mys) mouse set slovnik(skok) jump
Pole lze samozřejmě plnit i pomocí smyčky. while {$i<10} {set a($i) $i; incr i}
Pro práci s poli je k dispozici několik funkcí, z nichž ty nejvýznamnější jsou uvedeny v následující tabulce. Všechny funkce začínají příkazem array, který jako svůj první parametr vyžaduje název operace, jež se má s polem provést. Název funkce array get pole array get pole vzor array names pole array names pole vzor array set pole seznam array exists pole array size pole
Význam funkce vrací všechny hodnoty klíčů i prvků pole vrací všechny hodnoty klíčů i prvků pole, kde klíče odpovídají zadanému vzoru vrací všechny klíče (indexy) pole vrací všechny klíče pole, které odpovídají zadanému vzoru vytváří pole ze seznamu (indexuje se automaticky) provede ověření (predikát), zda existuje pole o zadaném názvu - vrací řetězec 0 nebo 1 vrátí počet prvků v poli - vhodné pro počítané smyčky
array set icolor { red 1 green 5 blue 4 white 9 } puts $icolor(red)
Vytvoří pole barev a jejich hodnot a vypíše hodnotu pro „red“ 1.
10
Za povšimnutí stojí příkaz array get pole, kterým je možné převádět pole na seznam. Kromě výše zmíněných příkazů lze vyhledávat prvky v poli pomocí voleb startsearch, donesearch a nextelement. V některých případech je však vhodnější převést pole na seznam a procházet seznamem pomocí smyčky foreach. Seznamy Seznam se od polí liší zejména v tom, že jeho prvky mohou být libovolného typu, například další seznamy. Rekurzivním vkládáním seznamů do sebe lze z původně lineární datové struktury vytvořit například binární či n-ární strom. Seznam se vytvoří velmi jednoduše pomocí příkazu set. set seznam1 { 1 2 3 4 5 6 } set seznam2 { jedna dve tri ctyri pet sest } set seznam3 { 1 {2 3} {4 5} {6 7} {8} } Název funkce list concat llength split join lappend linsert lindex lreplace lrange lsearch lsort
Význam funkce vytvoření seznamu z argumentů, které jsou tomuto příkazu zadány spojení dvou a více seznamů získání počtu prvků v seznamu rozložení řetězce na seznam buď podle bílých znaků nebo podle specifikovaného oddělovače vytvoření řetězce spojením prvků seznamu, mezi něž se může volitelně vložit oddělovač přidání jednoho či více prvků do seznamu vložení jednoho či více prvků na danou pozici (index) získání prvku ze seznamu na dané pozici (indexu) nahrazení prvků v seznamu vyjmutí více prvků ze seznamu (souvislá oblast) hledání prvků v seznamu (možné i podle regulárních výrazů!) setřídění prvků v seznamu podle zadaných kritérií
Funkce pro práci se seznamy
Práce s řetězci Regulární výrazy V Tcl jsou podporovány dva typy regulárních výrazů. První typ, nazývaný také glob matching, v mnohém odpovídá regulárním výrazům známým z unixového shellu. Druhý typ regulárních výrazů, který je složitější, zhruba odpovídá regulárním výrazům použitým v textovém editoru Vim, vyhledávací utilitě grep atd. V regulárních výrazech prvního typu se mohou vyskytovat následující zástupné znaky: Znak * ? [...] \znak další znaky
Význam znaku libovolně dlouhá sekvence znaků libovolný znak (pouze jeden) libovolný znak ze zadané množiny (lze použít i interval) odstranění speciálního významu výše zmíněných zástupných znaků další znaky se s řetězcem porovnávají bez dalšího zpracování
Zástupné znaky v regulárních výrazech prvního typu (ala shell)
11
Regulární výrazy druhého typu jsou použity například v dále uvedených příkazech regexp a regsub. Možností pro specifikaci řetězců zde existuje více. Znak . * + | [...] ^ $ \znak další znaky
Význam znaku libovolný znak nula či více výskytů předchozí položky jeden či více výskytů předchozí položky volba mezi dvěma výrazy (or) libovolný znak ze zadané množiny (lze použít i interval) začátek řetězce (uvnitř závorek funguje jako negace) konec řetězce odstranění speciálního významu zástupného znaku další znaky se s řetězcem porovnávají bez dalšího zpracování
Zástupné znaky v regulárních výrazech druhého typu (ala Vim) Název funkce Význam funkce vyhledání shody v řetězci podle zadaného regulárního výrazu (zde se používá kompletní repertoár značek v regulárním výrazu) regexp vyhledání shody v řetězci podle zadaného regulárního výrazu a zápis nového řetězce regsub do zadané proměnné
funkce pracující s regulárními výrazy Volba -all -inline -line
Význam volby porovnání všech výskytů vzoru v řetězci způsobuje, že výsledek funkce regexp je vrácen jako seznam zapíná rozšířené porovnávaní pro řetězce obsahující řádkování
volby pro regexp a regsub set veta "Jenda Mrazek\nKarel Holy" puts [regexp –all –inline –line "^.* " $veta]
Vyrobí seznam a vypíše {Jenda } {Karel } set veta "jenda je proste jenda" regsub -all {jenda} $veta cisco veta puts $veta
Nahradí v řetězci v proměnné veta všechny výskyty „jenda“ za „cisco“ a vypíše „cisco je proste cisco“ Funkce pro práci s řetězci Tyto funkce si můžeme rozdělit do dvou kategorií - funkce volané přímo svým jménem a "podpříkazy" funkce string. Nejprve si uvedeme, které funkce pro práci s řetězci je možné volat přímo: Název funkce Význam funkce append pomocí této funkce je možné přidat znaky na konec řetězce funkce pro manipulaci s řetězcem s mnoha dalšími volbami uvedenými v následující string tabulce format formátování řetězce ve stylu C-čkovské funkce printf() scan čtení hodnot z řetězce ve stylu C-čkovské funkce sscanf()
Funkce pro práci s řetězci
12
set znaky 1 append znaky b puts $znaky
Uloží do proměnné znaky 1 a přidá na jeho konec b, vypíše „1b“ set cena 10 set pocet 5 set nazev router puts [format "%ix %s za %.2fkc" $pocet $nazev $cena]
Vypíše „5x router za 10.00kc“ set veta "Petr ma 20 let." scan $veta "%s %*s %d" jmeno vek puts [format "%s , %d" $jmeno $vek]
Zpracuje řetězec z proměnné veta podle zadaného formátu a vypíše „Petr , 20“ funkce string V níže uvedené tabulce si uvedeme některé základní manipulace s řetězci, které lze provádět právě pomocí funkce string. Název funkce string length string index string first string last
Význam funkce tato funkce vrací délku řetězce pomocí této funkce lze získat znak na určité pozici, přičemž první znak má index nula vyhledávání prvního podřetězce v řetězci a vrácení indexu jeho začátku vyhledávání posledního výskytu podřetězce v řetězci a vrácení indexu pozice začátku lexikografické porovnání dvou řetězců (odpovídá C-čkovské funkci strcmp(), výstupní hodnoty jsou -1, 0 a 1) string compare porovnání řetězce se vzorem, přičemž je možné použít zjednodušených regulárních string match výrazů (podobně jako v shellu, výstupní hodnoty jsou 0 nebo 1) tato funkce vrací podřetězec zvolený dvěma indexy. Místo horního indexu lze použít i string range slovo end (to se vyhodnotí jako expr [string length] -1) tato funkce vrací řetězec odpovídající původnímu řetězci, přičemž se provádí převod na malá písmena - minusky (funguje i pro češtinu) string tolower obdoba předchozí funkce s tím, že se zde provádí převod na kapitálky (opět string toupper podporuje češtinu) tato funkce vrací podřetězec, ze kterého jsou odstraněny vybrané počáteční a koncové znaky string trim string trimleft obdoba předchozí funkce s tím rozdílem, že se odstraňují pouze počáteční znaky string trimright odstranění pouze koncových znaků string wordstart tato funkce vrací index prvního znaku slova, které obsahuje zadanou pozici obdoba předchozí funkce, zde se však vrací index znaku, jež se nachází ihned za string wordend slovem Nejpoužívanější volby funkce string podrobněji puts [string length cisco]
Vypíše délku řetězce „cisco“, 5 puts [string index cisco 1]
Vypíše písmeno v řetězci „cisco“ na indexu 1, i puts [string first c cisco]
Vypíše index prvního výskytu „c“ v řetězci „cisco“, 0
13
puts [string last c cisco]
Vypíše index posledního výskytu „c“ v řetězci „cisco“, 3 puts [string compare cisco Cisco] puts [string compare -nocase cisco Cisco]
Vypíše výsledek porovnání řetězců „cisco“ a „Cisco“, v prvním případě vypíše 1, protože má první řetězec větší váhu (pořadí písmen) než druhý, v druhém případě, za použití volby -nocase vypíše 0, protože se ignorují velká a malá písmena a řetězce jsou tedy stejné. puts [string match c* cisco]
Vypíše 1, protože řetězec „cisco“ začíná na „c“ a následují libovolné znaky puts [string range cisco 1 2]
Vypíše z řetězce „cisco“ řetězec z intervalu indexu <1,2>, „is” puts [string toupper cisco] puts [string tolower CiscO]
Vypíše „CISCO“ a „cisco“ puts [string trim xciscox x] puts [string trimleft xxcisco xx] puts [string trimright cisco, ,]
Ve všech případech vypíše „cisco“, pokud neuvedu řetězec, který chci odstranit, zpracovávají se standardně mezery. puts [string wordstart "xxl cisco" 5] puts [string wordend "xxl cisco" 5]
Index odkazuje na písmeno i, v prvním případě nám vypíše index začátku slova obsahující zmíněné i „cisco“, 4, ve druhém index konce tohoto slova, 9.
Poznámky k CISCO implementaci Pomocí příkazu exec můžeme provést příkaz v IOS v privilegovaném režimu. exec "show interfaces"
Pro modifikaci konfigurace routeru se používá příkaz ios_config. Pro nastavení parametru v nějaké zanořené konfigurační části (např. změna stavu rozhraní), bude první parametr popisovat konfigurační část a druhý parametr aktuální příkaz z konfigurační části. ios_config "interface Ethernet 0/0" "no shutdown" ios_config "router bgp 1 address-family vpnv4" "neighbor 10.1.1.1 activate"
Pokud je první parametr příkazu ios_config, příkazem z globálního konfiguračního režimu, měli by jsme druhý parametr vynechat. ios_config "hostname RA"
Jde provést i několik příkazů v jednom řádku. ios_config "interface loopback 111" "ip address 1.2.3.4 255.255.255.255" → "description Test" "ip ospf cost 20"
Pro automatizaci Tcl skriptů obsahuje IOS Embedded Event Manager, který poskytuje možnost monitorování událostí a provedení akcí po jejich vzniku. Pro využívaní balíčků, které EEM nabízí musí být skript spouštěn přes EEM (v TCL shellu tclsh nejsou dostupné). 14
Nejspíše z bezpečnostních důvodů nelze v EEM použít příkaz exec, místo něj se používá funkce cli_write. Funkce cli_write, která je dostupná pouze pokud skript spouštím přes EEM, funguje jako poslaní příkazu na příkazový řádek IOS. Pokud se tedy chci dostat např. do konfiguračního režimu, musím tam poslat příkazy postupně ("enable", "configure terminal" - funguje i zkrácený zápis "en", "config t").
Spouštění Tcl příkazů Postup spouštění jednotlivých TCL příkazů: 1. Vstup do privilegovaného EXEC režimu enable 2. (Volitelný) vstup do globálního konfiguračního módu configure terminal 3. (Volitelné) specifikování inicializačního skriptu, který se má spustit, když se aktivuje TCL shell (příkazem tclsh): scripting tcl init
4. Opuštění globálního konfiguračního módu exit 5. Povolení interaktivního TCL shellu a vstup do Tcl konfiguračního módu, ve kterém je možno zadávat Tcl příkazy: tclsh 6. Zadání příkazu Tcl 7. Opuštění Tcl konfiguračního módu a návrat do privilegovaného EXEC režimu: exit Předefinovaný skript se spustí z privilegovaného EXEC režimu pomocí CLI příkazu tclsh device:skript.tcl (kde device je zařízení, na kterém je Tcl skript umístěn). skript Hello.tcl na serveru s IP adresou 192.168.0.10 TFPT tclsh tftp://192.168.0.10/Hello.tcl FTP tclsh ftp://user:[email protected]/Hello.tcl
Použité zdroje ROOT.cz - Seriál Programovací jazyk TCL http://www.root.cz/serialy/programovaci-jazyk-tcl/ Ulivelli, Kordas - Možností použití skriptování v jazyku Tcl v Cisco IOS http://www.cs.vsb.cz/grygarek/SPS/projekty0607/TCL-Kordas.pdf CISCO - Cisco IOS Scripting with Tcl http://www.cisco.com/univercd/cc/td/doc/product/software/ios123/123newft/123t/123t_2/gt_t cl.pdf
15
Příklady
Vypsání názvu všech BRI rozhraní oddělených čárkou
1. přechod do tcl shellu tclsh 2. vložení procedury proc get_bri {} { set check "" set int_out [exec "show interfaces"] foreach int [regexp -all -line -inline "(^BRI\[0-9]/\[0-9])" $int_out] { if {![string equal $check $int]} { if {[info exists bri_out]} { append bri_out "," $int } else { set bri_out $int } set check $int } } return $bri_out } 3. zavolání vložené procedury get_bri
ping na zadané ip adresy, v případě, že je úspěšnost pingu menší než zvloená hodnota v procentech, provede se odeslání emailu na zadané emailové adresy. Soubor pinger.tcl je uložen na tftp serveru (v naší ukázce má adresu 192.168.1.1).
1. obsah souboru pinger.tcl ::cisco::eem::event_register_timer watchdog name pinger time → $EEM_PINGER_INTERVAL package provide pinger 1.0 namespace import ::cisco::eem::* namespace eval ::pinger { # funkce, ktere jsou z balicku dostupne namespace export initialize sendmessage ping # vychozi hodnoty pro smtp array set ::pinger::sendmail { smtphost smtp.vsb.cz from [email protected] friendly "Router A" } # procedura pro zmenu vychozich hodnot smtp # smtphost – smtp server # from – adresa odesilatele # friendly – jmeno odesilatele proc initialize {smtphost from friendly} { variable sendmail if {[string length $smtphost]} then { set sendmail(smtphost) $smtphost } if {[string length $from]} then { set sendmail(from) $from } if {[string length $friendly]} then { set sendmail(friendly) $friendly
16
} } # procedura pro odeslani emailu # toList – seznam prijemcu emailu # subject – predmet emailu # body – text emailu proc sendmessage {toList subject body} { variable sendmail set smtphost $sendmail(smtphost) set from $sendmail(from) set friendly $sendmail(friendly) if {[catch {socket $smtphost 25} result]} { puts stdout "smtp socket opening error \[$smtphost:25\]" return -1 } else { set sockid $result } set status [catch { puts $sockid "HELO $smtphost" flush $sockid set result [gets $sockid] puts $sockid "MAIL From:<$from>" flush $sockid set result [gets $sockid] foreach to $toList { puts $sockid "RCPT To:<$to>" flush $sockid } set result [gets $sockid] puts $sockid "DATA " flush $sockid set result [gets $sockid] puts $sockid "From: $friendly <$from>" foreach to $toList { puts $sockid "To:<$to>" } puts $sockid "Subject: $subject" puts $sockid "\n" foreach line [split $body "\n"] { puts $sockid " $line" } puts $sockid "." puts $sockid "QUIT" flush $sockid set result [gets $sockid] } result] catch {close $sockid} if {$status} then { error $result "Sending email..." } return }
17
# procedura pro ping adresy # address – ip adresa nebo hostname pro ping proc ping {address} { if {[catch {cli_open} result]} { error $result "opening cli" } else { array set cli $result } if [catch {cli_exec $cli(fd) "ping $address"} result] { error $result "executing cli command ping" } else { set ping [regexp -line -inline "^Success.*$" $result] } if [catch {cli_close $cli(fd) $cli(tty_id)} result] { error $result "closing cli" } set success -1 if {[string length $ping]} { set f [expr [string first "is" $ping]+3] set l [expr [string first "percent" $ping]-2] set success [string range $ping $f $l] } return $success } } # seznam prijemcu set toList {[email protected]} # seznam testovacich ip adres set ipList {158.196.44.1 homel.vsb.cz 158.196.44.26 158.196.44.27} # pozadovana minimalni uroven uspechu pingu v procentech set pingThreshold 50 foreach ip $ipList { set rate [pinger::ping $ip] if {$rate < 0} { puts stdout "ping success error ($ip)!" } elseif {$rate < $pingThreshold} { puts stdout [format "%3i%% %s: below %i%%, sending email" $rate $ip → pingThreshold] pinger::sendmessage $toList Warning "Ping success rate on address $ip → is $rate percent." } else { puts stdout [format "%3i%% %s" $rate $ip] } } 2. přepnutí do privilegovaného režimu enable 3. zkopírování souboru pinger.tcl ze tftp serveru na adrese 192.168.1.1 do flash paměti routeru copy tftp://192.168.1.1/pinger.tcl flash: 4. vstup do konfiguračního režimu configure terminal 5. nastavení cesty pro uživatelské tcl skripty EEM event manager directory user policy flash: 6. nastavení proměnné pro čas opakování pingu EEM_PINGER_INTERVAL na 30s event manager environment EEM_PINGER_INTERVAL 30 7. přidaní skriptu do EEM a tím i jeho inicializaci event manager policy pinger.tcl
18