1

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?

3
  • for arg in ${param[@]}; do <- try this, but not sure if it would. one more question why $arg*? Commented Jan 9, 2020 at 4:45
  • I am still getting the same error. i use $arg* just in case there are file like a.txt.backup, etc. Commented Jan 9, 2020 at 4:50
  • One issue is your array set is incorrect. In expect array seems being set as list and expect even number of item to be set. And if you access as ${!my_file[@]}, it would return only indexes; and the given answer has some issues, but seems to be valid Commented Jan 9, 2020 at 5:11

2 Answers 2

2

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

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your explanation.. I am trying to trace all manually and found out that the problem is how to make array in bash can accept for expect. i tried to use {${my_file[@]}} but the result is array is being undefined.
It works for me (granted, where I use cat instead of expect), perhaps some unrelated part of your script is interfering? But if you are hard-coding the array in the script, you might as well hard-code it directly into the Expect script.
I edited my post with added full code, perhaps that provide better info. I am just lost right now lol
How do you conclude that the problem is in the Expect script? Can you print the array just before the Expect part and verify that it contains what you want?
@nawanTSL : You are creating a Tcl program which will kind of preprocessed by bash (by interpolating the bash variables). The solution by tripleee sounds reasonable, but if you still get an error, I suggest that you split the problem into two steps: First create (using your HERE-document) a variable or file holding the resulting Tcl/expect program, and then write this file to stdout before invoking expect in it. With this, you can see whether the variable substitution as been indeed performed in the way you expected.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.