Cisco show | section megvalósítása bash-ben (bash+sed+awk)

Sziasztok!

Nem is tudom milyen topikban van ennek a helye, mert félig networking
félig scripting a téma. A következőt szeretném megvalósítani: Cisco
CLI-ben a konfig megjelenítését a show run | section router ospf
paranccsal lehet szűkíteni úgy, hogy csak a router ospf alatt levő
parancsok jelennek meg melynek alapja, hogy a router ospf alatt
a következő "section" újra betűvel kezdődik (mármint a sor) valamint
minden OSPF parancs egy space-el bentebb van, valahogy így ugye:
/Csak azért írom le, hogy ha Cisco CLI-ben járatlan DE bash+sed+awk-
ban jártas ember látja ezt akkor ő is tudjon segíteni :) /


R6#sh run | section router ospf
router ospf 1
 router-id 50.0.0.6
 log-adjacency-changes
 network 50.0.0.0 0.0.0.255 area 0
 network 192.168.0.0 0.0.0.255 area 0
 network 192.168.2.0 0.0.0.255 area 0

Nos, hasonlót akarok megvalósítani linuxon, bashben, konfigfile-
ok megjelenítésére, kimenet szűrésére. Erre ezt találtam ki:

Ez valósítja meg a "section"-t:


[crok@clifford ~]$ cat section 
#!/bin/bash
#
# Ki kell cserélni az esetleges "/"-t a kérésben
# mint pl. "int fa 0/0" - ez 3 paraméter, de a
# harmadikban pl. a "/" az regex metakarakter..
#
FIRST=$(echo $1 | sed 's,/,\\/,g') 
SECOND=$(echo $2 | sed 's,/,\\/,g')
THIRD=$(echo $3 | sed 's,/,\\/,g')
FOURTH=$(echo $4 | sed 's,/,\\/,g')
#
# És maga a parancs:
sed -n '/'^"$FIRST".*"$SECOND".*"$THIRD".*"$FOURT"'/,/^[a-z]/p' | sed '$d'

Csináltam 2 alias-t is:


alias s='~/./section '
alias sh='cat '

..ami egy mentett konfig fa 0/1 interface konfigját így jeleníti meg:


[crok@clifford ~]$ sh temp/1.txt | s int fa 0/1
interface FastEthernet0/1
 description LAN
 ip address 10.10.10.1 255.255.255.0
 ip access-group LAN in
 no ip redirects
 no ip unreachables
 no ip proxy-arp
 ip accounting output-packets
 ip accounting mac-address input
 ip accounting mac-address output
 ip nbar protocol-discovery
 ip nat inside
 ip virtual-reassembly
 zone-member security LAN
 ip route-cache flow
 duplex auto
 speed auto
 arp probe interval 10 count 3
 arp authorized
 arp timeout 3600

..ami korrekt is. Kérdés: lehet ezt egyszerűbben?

(Megjegyzés: Elnézést, ha nagyon körülírtam vagy nagyon pongyolán
fogalmaztam, csak kettős az hallgatóság/olvasói kör, akinek írok..)

Hozzászólások

Ami nekem szemet szúr, szerencse, hogy csak 4 paraméter van:

esc() {
    sed 's,/,\\/,g' <<<"$1"
}

sed -n "/^`esc $1`".*"`esc $2`".*"`esc $3`".*"`esc $4`/,/^[a-z]/p" | sed '$d'

Valami ilyesmire gondolok, azért nézd át.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Azért csak 4 mert nem szoktam sose többet használni - igazából minden
értelmeset ki lehet szedni 4 paraméterrel (szerintem). De igaz, így
lehet rajta finomítani, általánosabbá tenni, ciklussal újraírni a teljes
paraméterlistát, az összes (akár "végtelen") paraméterrel és azt átadni
a sed-nek - de nekem 4 paraméter elég, az interface kiíratása is csak 3.

---------
http://evilrouters.net/2011/10/27/choose-internetworking/

Azok a .*-ok a shellnek szóló globok?

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Igen, így "általánosítok és lustaságot adok" a felhasználónak, hogy ne
kelljen kiírni, hogy "interface" meg "fastethernet", így elég, ha csak
"int" és "fa", vagy pl. "router" "eigrp" helyett csak "ro" "ei" - így jobban
hasonlít a Cisco CLI-re.

---------
http://evilrouters.net/2011/10/27/choose-internetworking/

Változó paraméterszámra valami ilyesmi:

par=''
while [ $# -gt 0 ]; do
    par="${par}`sed 's,/,\\/,g' <<<"$1"`"
    [ $# -gt 1 ] && par="${par}.*"
    shift
done
sed -n "/^${par}/,/^[a-z]/p" | sed '$d'

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Remek! Ez ugyan nem cserélte le a "/"-eket "\/"-re, de ez már jó:


#!/bin/bash
esc() {
    sed 's,/,\\/,g' <<<"$1"
}
par=''
while [ $# -gt 0 ]; do
    par="${par}`sed 's,/,\\/,g' <<<"$1"`"
    [ $# -gt 1 ] && par="${par}.*"
    shift
done
sed -n '/'^`esc ${par}`'/,/^[a-z]/p' | sed '$d'

---------
http://evilrouters.net/2011/10/27/choose-internetworking/

Na várj! Lehet, hogy elnéztem a backslash-ek számát, de ahogy írod, úgy kicsit sok a sed. Viszont rávilágítottál arra, hogy a stringként előállított regexpet elég lenne egyetlen alkalommal escape-elni, teljesen felesleges paraméterenként tenni ezt. Mindjárt reszelek rajta, bár nem próbálom ki, ezért aztán olykor zöldség lesz belőle. :)

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Szerintem az esc() függvényben volt sok a backslash. Neked azért működött, mert a helyettesítést nem raktad idézőjelbe, s akkor tényleg két backslash kell, de nekem csak egy, mert idézőjelen belülre tettem:

#!/bin/bash

esc() {
    sed 's,/,\/,g' <<<"$1"
}

par=''
while [ $# -gt 0 ]; do
    par="$par$1"
    [ $# -gt 1 ] && par="${par}.*"
    shift
done
sed -n "/^`esc $par`/,/^[a-z]/p" | sed '$d'

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Majdnem :] Emígyen jó - az esc-ben lemaradt
egy "\" escape-elni az escape karaktert:


#!/bin/bash
esc() {
    sed 's,/,\\/,g' <<<"$1"
}
par=''
while [ $# -gt 0 ]; do
    par="$par$1"
    [ $# -gt 1 ] && par="${par}.*"
    shift
done
sed -n "/^`esc $par`/,/^[a-z]/p" | sed '$d'

..és így már gyönyörűen működik! :] Köszönöm!

---------
http://evilrouters.net/2011/10/27/choose-internetworking/


Kicsit alakítottam rajta:

alias s='./section'
alias sh='cat '

cat section
#!/bin/bash
esc() {
    sed 's,/,\\/,g' <<<"$1"
}
par=''
while [ $# -gt 0 ]; do
    par="$par$1"
    [ $# -gt 1 ] && par="${par}.*"
    shift
done
awkpar=$(esc $par)
awk -v IGNORECASE="1" '/^[[:alnum:]_]|!/ {p=0} /'$awkpar'/ {p=1} p'


Használat közben ilyesmi a kimenete:
$ sh router.config | s int ten 1/1
interface TenGigabitEthernet1/1
 switchport
 <..blahblahblah.. et cetera..>
 wrr-queue queue-limit 15 1 19 10 15 2 3
 wrr-queue random-detect min-threshold 1 80 100 100 100
 <..blahblahblah.. et cetera..>
 wrr-queue dscp-map 4 1 18 30
 wrr-queue dscp-map 5 1 34 35 36 37 38


---------
http://evilrouters.net/2011/10/27/choose-internetworking/