1

Error while executing send if command, Not sure if I'm missing some tcl syntax.

#!/usr/bin/expect -f
# Get the list of hosts, one per line #####
set f [open "/tmp/host.txt"]
set hosts [read $f]
close $f

# Iterate over the hosts
foreach host $hosts {
spawn ssh $host
expect "password: "
send "abcd@123\r"
expect "$ "
send "if [ `df -Ph / | grep -vE '^Filesystem' | awk '{ print $5 " " $1 }' |cut -d'%' -f1` -ge 60 ] ;then  echo "Hi Team- Please check root file system space on `hostname` " | mailx -s "Alert: Almost out of disk space on `hostname`" zoom@oracle.com ;fi\r" 
expect "$ " 
send "exit\r" 
expect eof     }

===Error===

[root@hzavks01~]# extra characters after close-quote
    while executing
"send "if [ `df -Ph / | grep -vE '^Filesystem' | awk '{ print $5 " " $1 }' |cut -d'%' -f1` -ge 60 ] ;then  echo "Hi Team- Please check root file system..."
    ("foreach" body line 6)
    invoked from within
"foreach host $hosts {
spawn ssh $host
expect "password: "
send "abcd@123\r"
expect "$ "
send "if [ `df -Ph / | grep -vE '^Filesystem' | awk '{ print $5..."
    (file "./test.sh" line 10)
  • The string that you use with send seems to contain double quotes. I'm not sure what expect does with double-quoted strings that contain double quotes, but a guess is that you would have to escape the internal ones as \". – Kusalananda Oct 30 '18 at 7:52
  • I tried escaping all the internal " but didn't fixed. I guess missing some syntax for escaping characters in tcl – muku Oct 30 '18 at 7:55
  • 1
    instead of send "...\r" write send {...}; send "\r" (that is, put everything in braces instead of double quotes, except for the CR, which you send separately). Otherwise, tcl will also try to expand the $5 and $1 from the awk command, even if you try to escape the double quotes inside "...". – mosvy Oct 30 '18 at 8:16
  • and if you use braces {...} instead of double quotes "...", do not escape " as \". – mosvy Oct 30 '18 at 8:24
  • Tcl/Expect syntax is quite tricky. take a look at sexpect with which you can write Expect scripts with shell code only. – pynexj Oct 30 '18 at 9:54
1

TCL is simple. In this case as mosvy indicates in the comments use {...} to disable interpolation of the tricky shell code. However the \r to input the command must not be escaped, and the send procedure wants a single string, so either join the string together or use two send calls:

#!/usr/bin/env expect
catch {exec rm foo}
log_file expect.log
spawn -noecho sh
expect -ex {$ }
send {df | awk '/\//{print $NF}' > foo}
send "\r"
expect -ex {$ }
send -- {exit}
send "\r"
expect eof

This might be improved on with a sendline procedure for the task that keeps the \r bit from cluttering up the code:

#!/usr/bin/env expect
proc sendline {line} { send -- "$line\r" }
spawn -noecho sh
expect -ex {$ }
sendline {df | awk '/\//{print $NF}' > foo}
expect -ex {$ }
sendline "exit"
expect eof

If you do need interpolation then backwhacking will be necessary, though in that case it might be better to eliminate the shell code and instead call a program directly on the remote system that performs the necessary task or produces the necessary output in an easy to consume form.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.