Part of my expect script searches on a remote host a text file,
named in variable $hosttab, for IP addresses, stored as, say
a.b.c.d HOSTNAME
where the HOSTNAME itself is stored in variable $hostname.
I would like to extract that IP address and then use this
address in further commands in my script.
I don't see how I can extract the IP address. Here is so
far I got:
spawn "telnet ..."
...
send "egrep ' $hostname\$' $hosttab\r"
expect -re "([0-9.]*) *$hostname" { set ipaddr ????? }
What do I have to put in the place of the question marks
in order to refer to the string matching the part of the
regexp in parentheses? In Perl, I would use $1, but I didn't
find a similar mechanism documented for 'expect'.
Or is my approach entirely wrong? All examples which I
studied, used $expect_out to catch part of the result,
but I don't think I can use it here, because expect_out
is documented as containing the output which has not
been matched yet, and I would like to catch part of
what has already matched.
Ronald
--
Sent by mn-pg-p-e-b-consultant-3.com from siemens in field com
This is a spam protected message. Please answer with reference header.
Posted via http://www.usenet-replayer.com
no expect_out is what you want, read the man pages again.
Here's an excerpt from them:
Upon matching a pattern (or eof or full_buffer), any matching and
previously unmatched output is saved in the variable expect_out(buffer).
Up to 9 regexp substring matches are saved in the variables
expect_out(1,string) through expect_out(9,string). If the -indices flag
is used before a pattern, the starting and ending indices (in a form
suitable for lrange) of the 10 strings are stored in the variables
expect_out(X,start) and expect_out(X,end) where X is a digit,
corresponds to the substring position in the buffer. 0 refers to strings
which matched the entire pattern and is generated for glob patterns as
well as regexp patterns. For example, if a process has produced output
of "abcdefgh\n", the result of:
expect "cd"
is as if the following statements had executed:
set expect_out(0,string) cd
set expect_out(buffer) abcd
and "efgh\n" is left in the output buffer. If a process produced
the output "abbbcabkkkka\n", the result of:
expect -indices -re "b(b*).*(k+)"
is as if the following statements had executed:
set expect_out(0,start) 1
set expect_out(0,end) 10
set expect_out(0,string) bbbcabkkkk
set expect_out(1,start) 2
set expect_out(1,end) 3
set expect_out(1,string) bb
set expect_out(2,start) 10
set expect_out(2,end) 10
set expect_out(2,string) k
set expect_out(buffer) abbbcabkkkk
and "a\n" is left in the output buffer. The pattern "*" (and -re
".*") will flush the output buffer without reading any more output from
the process.
Normally, the matched output is discarded from Expect's internal
buffers. This may be prevented by prefixing a pattern with the
-notransfer flag. This flag is especially useful in experimenting (and
can be abbreviated to "-n" for convenience while experimenting).
> If a process produced
> the output "abbbcabkkkka\n", the result of:
>
> expect -indices -re "b(b*).*(k+)"
>
> is as if the following statements had executed:
>
> set expect_out(0,start) 1
> set expect_out(0,end) 10
> set expect_out(0,string) bbbcabkkkk
> set expect_out(1,start) 2
> set expect_out(1,end) 3
> set expect_out(1,string) bb
Thank you for pointing this out! I tried to use it like this in my
script:
# Do something like:
# fgrep myhost /etc/hosts
# fgrep is supposed to return something like
# 10.168.40.24 myhost
# We use the regexp ([0-9.]+) *myhost to extract
# the IP address
send "fgrep $hostname $hosttab\r"
expect -indices -re [join {([0-9.]+) *} $hostname]
# The next two lines are only for testing
set result $expect_out(buffer)
puts "Received: <$result>"
puts "Matched part: <$expect_out(1,string)>"
After this, $result indeed contains the full expected output, including
the
IP address, but usage of $expect_out(1,string), which should be the IP
address only, fails:
can't read "expect_out(1,string)": no such element in array
while executing
"puts "Matched part: <$expect_out(1,string)>""
What am I doing wrong?
Ronald
That use of [join] there can't be right. I don't know what you think it
is doing, but it isn't. (I wish I knew what I think it is doing, but it
just confuses me!) Try this:
expect -indices -re "(\[0-9.\]+) *$hostname"
OK, that might not work either, but it is at least probably closer to
what I suspect you intend...
Donal.
In your posting Re: How to extract part of what matched an expect
pattern? from Tue, 07 Feb 2006 11:02:21 +0000 you write:
>
> ro.nald...@gmail.com wrote:
> > expect -indices -re [join {([0-9.]+) *} $hostname]
>
> That use of [join] there can't be right. I don't know what you think it
> is doing, but it isn't. (I wish I knew what I think it is doing, but it
> just confuses me!)
The join has the following function:
I need a regexp pattern which looks like
([0-9.]+) *HOSTNAME
where HOSTNAME is the name of the host I'm looking for. I couldn't
use
"([0-9.]+) *$hostname"
because Tcl would then interpret [0-9.] as command interpolation.
I couldn't use
{([0-9.]+) *$hostname}
either, because $-Interpolation is not done between curly braces.
But I think I can use join, because join builds a string out
of its elements; hence,
[join {([0-9.]+) *} $hostname]
would take it's first argument, the string
([0-9.]+) *
append to it the hostname, and we have exactly the regexp for expect.
> Try this:
>
> expect -indices -re "(\[0-9.\]+) *$hostname"
I usually try to avoid \ escapes, because I personally find them
unpleasant to read, but if you prefer it this way, I implemented
this change. This has no effect on the result: I still get
can't read "expect_out(1,string)": no such element in array
while executing
"puts "Matched part: <$expect_out(1,string)>""
invoked from within
Note that the error is not with my regexp (because, as $expect_out(buffer)
shows, expect exactly matches what it is supposed to match). It is
that $expect_out(1,string) seems to be undefined.
Ronald
--
Spam protected message from:
Sent by mn-pg-p-e-b-consultant-3.com from siemens within field com
Posted via http://www.usenet-replayer.com
Have you actually tried that yet or are you speaking on theoritical
terms? What makes you think join appends strings to the end of another
string?
Join doesn't append anything, it joins list elements. It will treat its
first argument as a list and join them together with the second
argument. In the above case, ([0-9.])+) is the first list element, * is
the second list element.
To wit:
% set hostname "whatever"
whatever
% join {([0-9.]+) *} $hostname
([0-9.]+)whatever*
Notice how the space before the asterisk is lost and the asterisk comes
before the hostname. That is not what you say you want.
Doing something like the above is a bad habit to get into -- you
shouldn't use list commands on things that aren't a list. Your string
works, but there are many, many regexps that wouldn't work. If you think
this works and use the idiom regularly, eventually your code will break
on an unusual pattern.
--
Bryan Oakley
http://www.tclscripting.com
Actually, I found out *why* expect_out(1,string) did not work:
expect ran on a timeout, i.e. my regexp didn't match at all!
OK, so now the interesting question is, why doesn't it match?
I have created the following simplified script:
#!/usr/bin/expect
send "fgrep localhost /etc/hosts\r"
expect {
-re {([0-9.]+) *localhost} {puts "IP address is $expect_out(1,string)"}
timeout {puts "timeout occurred"}
}
and indeed, I get a "timeout occured" message. But if I execute
the fgrep manually, I get a matching line
$ fgrep localhost /etc/hosts
127.0.0.1 localhost
This line certainly should match the expect result (although,
as I see now, it might only match the last digit, 1; so a better
regexp would be {^ *([0-9.]+) *localhost} - but at least it SHOULD
match something).
Why does expect fail to match here?
Ronald
--
Spam protected message from:
Sent by mn-pg-p-e-b-consultant-3.com from siemens element from com
Posted via http://www.usenet-replayer.com
Ronald Fischer wrote:
> NEW FINDINGS!!!
>
> Actually, I found out *why* expect_out(1,string) did not work:
> expect ran on a timeout, i.e. my regexp didn't match at all!
>
> OK, so now the interesting question is, why doesn't it match?
> I have created the following simplified script:
>
> #!/usr/bin/expect
> send "fgrep localhost /etc/hosts\r"
> expect {
> -re {([0-9.]+) *localhost} {puts "IP address is $expect_out(1,string)"}
> timeout {puts "timeout occurred"}
> }
>
> and indeed, I get a "timeout occured" message. But if I execute
> the fgrep manually, I get a matching line
>
> $ fgrep localhost /etc/hosts
> 127.0.0.1 localhost
>
> This line certainly should match the expect result (although,
> as I see now, it might only match the last digit, 1; so a better
> regexp would be {^ *([0-9.]+) *localhost} - but at least it SHOULD
> match something).
>
> Why does expect fail to match here?
>
your expression is only matching spaces between the number and the name,
if there is a tab in there it will fail.
try {([0-9.]+)\s*localhost} and see if it works any better
Bruce
No, it doesn't. Actually, the problem must be more fundamental: I
changed
my testscript to the following
#!/usr/bin/expect
send "fgrep localhost /etc/hosts\r"
expect {
-re {([0-9.]+)\s*localhost} {puts "IP address is
$expect_out(1,string)"}
-re {[0-9]} {puts "Number found"}
-re {.} {puts "Something found"}
timeout {puts "timeout occurred"}
}
and even here, timeout occurs! It does not even match the regexp "."
Maybe someone on a Linux/Unix machine could try to run the above script
on his/her machine? "localhost" should be in /etc/hosts, so fgrep will
return a suitable result.
Ronald
You seem to be missing a [spawn] in there...
Donal.
I thought I need spawn only if connecting to a process where I have to
conduct a dialogue (in my original version, I use spawn because I
execute the commands via telnet, but I omitted that part in my
demonstration program).
Indeed, the modified program works:
#!/usr/bin/expect
spawn bash --norc
send "fgrep localhost /etc/hosts\r"
expect {
-re {([0-9.]+)\s*localhost} {puts "IP address is
$expect_out(1,string)"}
timeout {puts "timeout occurred"}
}
send "exit"
(outputs: IP address is 127.0.0.1)
So I had combined two errors: In my first script, I didn't pay
attention to tab characters,
and in my simplified script, I didn't pay attention to spawning.
Unfortunately this did not help with my original script: I still didn't
get the IP address
in that context. Now with my new knowledge, I rewrote my original
program like this:
# ~/bin/+ is a one-line script, containing the telnet command to
connect to
# the remote host.
spawn "$env(HOME)/bin/+"
expect "#"
send "fgrep $hostname $hosttab\r"
expect "\n"
expect {
-re "(\[0-9.\]+)\s*$hostname" { puts "IP address is
$expect_out(1,string)" }
timeout { puts "timeout occurred"}
}
Executing it, I receive the following output (leaving out details about
the
login dialogue to the remote host):
root@sb1-1:~# fgrep actomm /etc/hosts
10.168.40.240 actomm
root@sb1-1:~# timeout occurred
So you see that the fgrep returns a correct value, but still I get the
error
message "timeout occured". But when I hardcode the $hostname
into the regexp, i.e.
-re "(\[0-9.\]+)\s*actomm" { puts "IP address is
$expect_out(1,string)" }
suddenly it matches. This means that in the statement
expect {
-re "(\[0-9.\]+)\s*$hostname" { puts "IP address is
$expect_out(1,string)" }
timeout { puts "timeout occurred"}
}
$hostname is not substituted by the content of the variable hostname -
probably
because of the outer braces around the expect parameters. Maybe expect
does not evaluate its parameters.
So, could some kind soul show me how to write this expect statement in
a correct way?
Ronald
Ronald