Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to use a variable in expect body which embedded in a shell script

6,509 views
Skip to first unread message

rjma...@gmail.com

unread,
Jan 21, 2009, 4:01:23 AM1/21/09
to elli...@gmail.com
Hi all,

My question is how to use expect in a shell script. For example, here
is a little program, it just telnet to some host, and login root
automatically.

#!/bin/bash

echo "This is to test how to call expect in a shell"

#hostname=10.0.0.1

expect -c '
set timeout 15
spawn telnet 10.0.0.1
expect "login:" { send "root\r" }
expect "assword:" { send "abcd1234\r" }
interact
'

Can I use variable in the body of expect? Such as the 10.0.0.1 is a
variation passed to the shell scripts, like the following, actually
this is wrong, expect can't handle $hostname

#!/bin/bash

echo "This is to test how to call expect in a shell"

hostname=10.0.0.1

expect -c '
set timeout 15
spawn telnet $hostname
expect "login:" { send "root\r" }
expect "assword:" { send "abcd1234\r" }
interact
'

it will issue the following error.
[tina@kgardenia test]$ ./test.expect
This is to test how to call expect in a shell
can't read "hostname": no such variable
while executing
"spawn telnet $hostname"


Does anybody know how to use a variable in the body of the expect
code, which is embedded in a bash?

Many thanks to you all :D

Andreas Leitgeb

unread,
Jan 21, 2009, 5:14:38 AM1/21/09
to
rjma...@gmail.com <rjma...@gmail.com> wrote:
> Can I use variable in the body of expect? Such as the 10.0.0.1 is a
> variation passed to the shell scripts, like the following, actually
> this is wrong, expect can't handle $hostname

There are two approaches:
1.) per environment:

hostname=10.0.0.1; export hostname


expect -c '
set timeout 15

spawn telnet $env(hostname)
...
'
or:

hostname=10.0.0.1 expect -c '
... ditto with $env(hostname)
'

2.) by concatenating differently quoted strings in sh:

hostname=10.0.0.1
expect -c '
set timeout 15

spawn telnet '"$hostname"'
...
'

Andreas Leitgeb

unread,
Jan 21, 2009, 5:27:04 AM1/21/09
to
Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
> rjma...@gmail.com <rjma...@gmail.com> wrote:
>> Can I use variable in the body of expect? Such as the 10.0.0.1 is a
>> variation passed to the shell scripts, like the following, actually
>> this is wrong, expect can't handle $hostname

More comments on my previous answer:


> There are two approaches:
> 1.) per environment:
> hostname=10.0.0.1; export hostname
> expect -c '
> set timeout 15
> spawn telnet $env(hostname)
> ...
> '

Unless you explicitly unset hostname after the call
to expect, you might pass the hostname also to other utilities
called from your script later. This is probably no problem
for the hostname, but could be for the password.

> hostname=10.0.0.1 expect -c '
> ... ditto with $env(hostname)
> '

In this case, hostname is only passed to expect as an environment
variable, and forgotten afterwards, so if you still need the hostname
afterwards in the sh-script, don't use it this way.

hostname=10.0.0.1
hostname=$hostname expect -c ' ... '
may appear moronic, but isn't at all. It leaves hostname
as a non-exported variable, while still sending it to expect.

> 2.) by concatenating differently quoted strings in sh:
> hostname=10.0.0.1
> expect -c '
> set timeout 15
> spawn telnet '"$hostname"'
> ...
> '

Actually, I'm sorry for having posted it at all, because it is maximally
unsafe. Any magic characters in the value of hostname could create havoc
inside expect, as expect sees its value as unquoted(!) part of the script
rather than as the contents of some variable or array.

For hostnames set explicitly in the shell-script this is a non-issue,
but I don't know, if this wasn't just a simplification of your problem
for posting.

Glenn Jackman

unread,
Jan 21, 2009, 7:27:27 AM1/21/09
to
At 2009-01-21 05:14AM, "Andreas Leitgeb" wrote:
> rjma...@gmail.com <rjma...@gmail.com> wrote:
> > Can I use variable in the body of expect? Such as the 10.0.0.1 is a
> > variation passed to the shell scripts, like the following, actually
> > this is wrong, expect can't handle $hostname
>
> There are two approaches:
> 1.) per environment:
[...]

>
> 2.) by concatenating differently quoted strings in sh:
[...]

3.) by constructing the expect script programmatically:

hostname=10.0.0.1
password=foobar
printf -v expect_script '
set timeout 15
spawn telnet %s
...
send -- "%s\r"
...
' "$hostname" "$password"
expect -c "$expect_script"


--
Glenn Jackman
Write a wise saying and your name will live forever. -- Anonymous

Andreas Leitgeb

unread,
Jan 21, 2009, 8:09:38 AM1/21/09
to
Glenn Jackman <gle...@ncf.ca> wrote:
>> 2.) by concatenating differently quoted strings in sh:
> [...]
> 3.) by constructing the expect script programmatically:
> hostname=10.0.0.1
> password=foobar

But my password happens to be:
password='hello\r"; exec nasty_command; #'

> printf -v expect_script '


> ...
> send -- "%s\r"
> ...

> ' ... "$password"
> expect -c "$expect_script"

Ouch. It shares the disadvantages that I wrote about 2nd way
in my previous direct followup.

It may be ok for a given case with a known-harmless hardcoded
password/hostname, but may be dangerous in other cases, like
where this data is entered by a foreign malvolent user.

Cameron Laird

unread,
Jan 21, 2009, 8:58:28 AM1/21/09
to
In article <slrngne55f...@smeagol.ncf.ca>,

Glenn Jackman <gle...@ncf.ca> wrote:
>At 2009-01-21 05:14AM, "Andreas Leitgeb" wrote:
>> rjma...@gmail.com <rjma...@gmail.com> wrote:
>> > Can I use variable in the body of expect? Such as the 10.0.0.1 is a
>> > variation passed to the shell scripts, like the following, actually
>> > this is wrong, expect can't handle $hostname
>>
>> There are two approaches:
>> 1.) per environment:
>[...]
>>
>> 2.) by concatenating differently quoted strings in sh:
>[...]
>
>3.) by constructing the expect script programmatically:
>
> hostname=10.0.0.1
> password=foobar
> printf -v expect_script '
> set timeout 15
> spawn telnet %s
> ...
> send -- "%s\r"
> ...
> ' "$hostname" "$password"
> expect -c "$expect_script"
.
.
.
... or by escaping fragile characters, or ...
In my speech, this thread is "about" bash and
Expect in only the most superficial syntactic
sense: it's merely a problem in quoting. To
summarize that "expect can't handle $hostname"
... well, it certainly confuses *me*.

Andreas Leitgeb

unread,
Jan 21, 2009, 10:28:12 AM1/21/09
to
Cameron Laird <cla...@lairds.us> wrote:
> ... or by escaping fragile characters, or ...
> In my speech, this thread is "about" bash and
> Expect in only the most superficial syntactic
> sense: it's merely a problem in quoting. To
> summarize that "expect can't handle $hostname"
> ... well, it certainly confuses *me*.

Point is, that by passing it over the environment,
(the first approaches in my response) all quoting
problems are moot.

Further safe approaches could involve passing in
information through expect's stdin, provided that
newline characters are not required to be allowed
parts of the actual data, and that the expect
script doesn't already read other data from stdin.

expect -c ' gets stdin hostname; ...' <<<"$hostname"

rjma...@gmail.com

unread,
Jan 22, 2009, 1:43:33 AM1/22/09
to
On Jan 21, 6:27 pm, Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at>
wrote:
> Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:

Thanks a lot for your prompt response. Does expect -c take things
between ' and ' as the code of expect? The code outside ' and ' will
be taken as shell, so "$hostname" was actually a shell style variable.
So you can just omit those two ", like


expect -c '
set timeout 15
spawn telnet '$hostname'
...
'

Am I right?

I agree this is dangerous if you don't know whether there are some
magic characters in the hostname.

Cameron Laird

unread,
Jan 22, 2009, 2:52:56 AM1/22/09
to
In article <a251d186-a70e-4b94...@n33g2000pri.googlegroups.com>,
<rjma...@gmail.com> wrote:
.
.

.
>Thanks a lot for your prompt response. Does expect -c take things
>between ' and ' as the code of expect? The code outside ' and ' will
>be taken as shell, so "$hostname" was actually a shell style variable.
>So you can just omit those two ", like
>expect -c '
>set timeout 15
>spawn telnet '$hostname'
>...
>'
>
>Am I right?
>
>I agree this is dangerous if you don't know whether there are some
>magic characters in the hostname.

You're wrong in a couple of minor ways, but, yes,

expect -c $ARG

interprets $ARG as an Expect command line --just as, for example,
<URL: http://www.tcl.tk/man/expect5.31/expect.1.html > promises.

Andreas Leitgeb

unread,
Jan 22, 2009, 5:02:19 AM1/22/09
to
rjma...@gmail.com <rjma...@gmail.com> wrote:
>> >      spawn telnet '"$hostname"'

>> Actually, I'm sorry for having posted it at all, because it is maximally
>> unsafe. ...

> Thanks a lot for your prompt response. Does expect -c take things
> between ' and ' as the code of expect?

Yes, and expect doesn't see the single quotes themselves.

> The code outside ' and ' will be taken as shell,

The shell, which also interprets the single-quotes according
to it's syntax (namely: "take everything literally, up to the
next single-quote") will also parse the "$hostname" and finally
create a single string that has all the parts concatenated, and
this string is then passed to expect, which takes it as if it
it had read it from a script-file.

> so "$hostname" was actually a shell style variable.

yes.

> So you can just omit those two ", like
> expect -c '
> set timeout 15
> spawn telnet '$hostname'

One principially can, but that has an effect on what the shell
does with the contents of the variable. For sh-like shells,
(unlike tclsh!), there *is* a difference between $var and "$var",
but this difference is only relevant for values of var that
contain certain shell-meta-characters such as e.g. whitespace.

0 new messages