nawanTSL
nawanTSL

Reputation: 85

How to loop Bash array in Expect script

I have an array in my bash script:

my_file=("a.txt" "b.txt" "c.txt" "d.txt" "e.txt")

Now in the same file I want to use Expect and make a looping to get some files in sftp. This is my code

/usr/bin/expect <<EOF
set timeout -1
array set param ${!my_file[@]}
spawn sftp $sftp_option $user@$host
expect "Password:"
send "$pswd\r"
expect "sftp>"
for arg in $param; do
send "mget $arg*\r"
expect "sftp>"
done
send "bye\r"
EOF

With that code I can't make a loop with that array above. And I got error like this:

wrong # args: should be "array set arrayName list" while executing "array set param 0 1"

Full Code:

#!/bin/bash

export PATH=$PATH:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin;

homeDir=/home/jlo_apps/daemon/jlo_ex/collection/wssh;
filePID=$homeDir/rsync_rfs_bbni.pid;

trap "rm $filePID; exit" SIGHUP SIGINT SIGTERM;

if [ -e $filePID ]; then
    datenow=`date`; 
    echo "[ Rsync ] There are rsync processes still running...";
    echo "========================= $datenow =========================";
    exit 1;
else
    echo $$ > $filePID;
fi

. $homeDir/get_rfs_bni.conf;

strconn="$dbuser/$dbpass@$dbhost:$dbport/$dbsid";

profile=`$sqlldr_path -s $strconn <<< "select host|| '|' ||username|| '|' ||password|| '|' ||port|| '|' ||outdir from p_epdp where bank='BBNI';" | tail -2 | head -1`;
mapfile mid < <($sqlldr_path -s $strconn <<< "select distinct(substr(mid, 0, 13)) from p_mid where kode_bank = 'BBNI';" | tail -3 | head -2);

host=$(echo $profile | cut -d"|" -f1);
user=$(echo $profile | cut -d"|" -f2);
pswd=$(echo $profile | cut -d"|" -f3);
port=$(echo $profile | cut -d"|" -f4);
outdir=$(echo $profile | cut -d"|" -f5);

/usr/bin/expect <<EOF
set timeout -1

spawn sftp $sftp_option $user@$host
expect "Password:"
send "$pswd\r"
expect "sftp>"
send "cd $outdir\r"
expect "sftp>"
send "lcd $rfshome\r"
expect "sftp>"
foreach arg {${mid[@]}} {
 send "mget $arg*\r"
 expect "sftp>"
}
send "bye\r"
EOF

rm $filePID;

sleep 10;

datenow=`date`; 
echo "========================= $datenow =========================";

Is there any solution for this problem without separate file between bash and Expect?

Upvotes: 1

Views: 3675

Answers (2)

glenn jackman
glenn jackman

Reputation: 246807

It's a bit awkward looking, but you can do this:

$ my_file=("a.txt" "b.txt" "c.txt" "d.txt" "e.txt")

$ expect -f - -- "${my_file[@]}" <<'END'
foreach arg $argv {puts $arg}
END
a.txt
b.txt
c.txt
d.txt
e.txt

The -f - tells expect to use stdin for the script file.
Then -- ends the command line options, and the remaining arguments go into the argv list.

Don't forget to use a quoted heredoc, like I demonstrate. Otherwise the shell will expand the expect variables.

Upvotes: 1

tripleee
tripleee

Reputation: 189387

The correct syntax to interpolate the array's values would be

array set param ${my_file[@]}

without a !, but this produces

array set param a.txt b.txt c.txt d.txt e.txt

However, the Expect syntax for creating an array looks like

array set param {one one.txt two two.txt}

with alternating keys and values (more like an associative array than just a list of values). But then you still can't use a shell for loop inside the Expect script; the language uses a completely different syntax (Expect is based on TCL, not shell script).

Probably you are looking for something like

/usr/bin/expect <<EOF
set timeout -1
spawn sftp $sftp_option $user@$host
expect "Password:"
send "$pswd\r"
expect "sftp>"
foreach arg {${my_file[@]}} {
 send "mget $arg*\r"
 expect "sftp>"
}
send "bye\r"
EOF

where I cribbed the proper TCL loop syntax from Pass bash array to expect script

Upvotes: 2

Related Questions