Quantcast
Channel: OSAKANA TAROのメモ帳
Viewing all articles
Browse latest Browse all 1106

expectでスクリプトを作った時のメモ書き

$
0
0

ssh経由の操作をexpectコマンドで自動化しようとした時に、expectで調べると、入出力関連に関しては出てくるが、文字列操作や制御構文周りがよくわからない。

ここら辺は、tclに関して調べるとわかるようになっている。

参考にしたサイト

LInux JM Home Page「expect (1)
FreeSoftNet 「Tcl>文法とコマンド
アプリコット PukiWiki「expectで自動化

if文の書き方

他の言語と同じように「if (条件){実行内容}」と書くと妙なエラーになる。

expectでは「if {条件} {実行内容}」というように、どちらも「{}」で囲む。
また、「if」と「{」の間、「条件の}」と「実行内容の{」の間のそれぞれにスペースを挟む必要がある。

文字列を比較して、異なる場合は「diff」、同じであれば「same」と出力するexpectは下記の様になる。

#!/usr/bin/expect -f
set hostnamenew "testhostnew"
set hostnamenow "testhost"

puts "hostnamenew: $hostnamenew"
puts "hostnamenow: $hostnamenow"

if { "$hostnamenew" != "$hostnamenow" } {
        puts "diff"
} else {
        puts "same"
}

誤って「if (条件) {実行内容}」とした場合、下記の様な「unbalanced open paren in expression」というエラーとなる。

unbalanced open paren
in expression "("
    (parsing expression "(")
    invoked from within
"if ( "$hostnamenew" != "$hostnamenow" ) {
        puts "diff"
} else {
        puts "same"
}"

「if(条件) {実行内容}」と「if{条件} {実行内容}」とifと{の間にスペースを入れない場合は下記のような「invalid command name」となる

invalid command name "if("
    while executing
"if( "$hostnamenew" != "$hostnamenow" ){"
invalid command name "if{"
    while executing
"if{ "$hostnamenew" != "$hostnamenow" }{"

面倒くさいことに「if {条件}{実行内容}」と、ifと条件の間にはスペース入れたけど、条件と実行内容の間にスペースがない場合は下記の「extra characters after close-brace while executing」というエラーになる。

extra characters after close-brace
    while executing
"if { "$hostnamenew" != "$hostnamenow" }{"

コマンド出力から文字列を取り出しと文字列の切り出し

expectを使う場合は、sshで他のホストに接続してコマンドを実行する、という用途で使うことが多い。

コマンドの実行結果によって、処理を変えたい場合、どうすればいいのか?

「expect -indices -re “条件式”」で条件式に該当した行を$expect_out(数字,string)で拾うみたいなんだけど、いまいち動作がよくわからない。

「ip a s ens160」を実行して、そのIPアドレスを取得したい場合の例として以下を作った

expect "\[#$] "
send -- "ip a s ens160\r"
expect -indices -re "inet (.*)\r"
puts "===buffer==="
puts "$expect_out(buffer)"
puts "===str0==="
puts "$expect_out(0,string)"
puts "===str1==="
puts "$expect_out(1,string)"
puts "===="

これの実行結果は下記となった。

2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:33:27:f8 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
===buffer===
ip a s ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:33:27:f8 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
===str0===
inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
===str1===
172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
====
       valid_lft forever preferred_lft forever
    inet6 fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

条件を「inet (.*)\r」から「inet6 (.*)\r」に変更

2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:33:27:f8 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
===buffer===
ip a s ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:33:27:f8 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
===str0===
inet6 fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
===str1===
fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
====

ここからさらにIPアドレスの部分を取り出すには「string first ~」「string last ~」と「string range ~」を使って文字列を切り出す。

set str $expect_out(1,string)
set stred [string first "/" $str]
puts "[string range $str 0 $stred]"
set stred [expr $stred - 1]
puts "[string range $str 0 $stred]"

上記の実行結果としては下記のようになる。

172.17.44.48/
172.17.44.48

他の言語のsubstring系だと開始アドレスと、そこを起点に取り出す文字列の長さを指定するが、tclのstring range では、開始アドレスと終了アドレスの2つを指定する形になるので注意が必要になる。


Viewing all articles
Browse latest Browse all 1106

Trending Articles