-2

I have automated most of the information required for the completion of this project but the only thing that is lagging is the running of local shell scripts on the remote machine.

As we are aware that no Linux command is recognized by the script that uses the 'expect' library.

Here in we have two use cases that I have tried:

  1. Running the desired list of commands on the remote server using only one expect script which has both the script execution as well as pushing of output using scp to the local machine, here is a snippet of this code:

    chmod 777 localscript.sh
    cat > script1.sh <<- "ALL"
    #!/usr/bin/expect
    set password [lindex $argv 0];
    set ipaddress [lindex $argv 1];
    set timevalue [lindex $argv 2];
    set timeout $timevalue
    spawn /usr/bin/ssh username@$ipaddress /bin/bash < ./localscript.sh
    expect "assword:"
    send "$password\r"
    set timeout $timevalue
    spawn /usr/bin/scp username@$2:"/path/from/source/*" /path/to/destination/folder/
    expect "assword:"
    send "$password\r"
    interact
    ALL
    chmod 777 script1.sh
    ./script1.sh $password $2 $timevalue
    
  2. Running the desired list of commands on the remote server in a separate expect script and using scp to get files in a different script:

    cat > script1.sh <<- "ALL"
    #!/usr/bin/expect
    set password [lindex $argv 0];
    set ipaddress [lindex $argv 1];
    set timevalue [lindex $argv 2];
    set timeout $timevalue
    spawn /usr/bin/ssh username@$ipaddress /bin/bash < ./localscript.sh
    expect "assword:"
    send "$password\r"
    interact
    ALL
    cat > script2.sh <<- "ALL2"
    #!/usr/bin/expect
    set password [lindex $argv 0];
    set ipaddress [lindex $argv 1];
    set timevalue [lindex $argv 2];
    set timeout $timevalue
    spawn /usr/bin/scp username@ipaddress:"/path/from/source/*" /path/to/destination/folder/
    expect "assword:"
    send "$password\r"
    interact
    ALL2
    chmod 777 localscript.sh script1.sh script2.sh
    ./script1.sh  $password $2 $timevalue
    sleep 5
    ./script2.sh  $password $2 $timevalue
    

==========================

I believe the above codes should both be valid in their own respect, however, the output for the same seem to be quite unexpected:

  1. Both the commands ssh and scp are being executed almost simultaneously after the password is entered hence, it is not giving localscript enough time to do its job, here's the output I see:

    spawn /usr/bin/ssh username@1.2.3.4 /bin/bash < ./localscript.sh
    Warning private system unauthorized users will be prosecuted.
    username@1.2.3.4's password: spawn /usr/bin/scp username@1.2.3.4:"/home/some/file/*" /another/file/
    Warning private system unauthorized users will be prosecuted.
    username@1.2.3.4's password:
    scp: /home/some/file/*: No such file or directory
    

Please note: This functionality is working fine without the involvement of 'expect'

  1. Here we are executing ssh and scp separately, however, it seems like it is unable to recognize that the file localscript.sh exists:

    spawn /usr/bin/ssh username@1.2.3.4 /bin/bash < ./localscript.sh
    Warning private system unauthorized users will be prosecuted.
    username@1.2.3.4's password:
    bash: localscript.sh: No such file or directory
    Warning private system unauthorized users will be prosecuted.
    username@1.2.3.4's password:
    scp: /home/some/file/*: No such file or directory
    

Any feedback on the same would be appreciated, I think the first approach might be a feasible solution, except the fact that spawn is too fast and none of the 'sleep' or 'after' commands are helping/working. I think the second approach is also valid however it seems like there is a different way of running a local script on a remote server than the usual way we do on Linux when using 'expect'.

  • Sorry about that, I raised that query in one of my udemy courses but was not able to find a response so I copied the same here, sorry for not truncating that information. – user307080 Aug 23 '18 at 14:36
0

Some notes:

  • the expect shebang line is wrong: # #!/usr/bin/expect should be just #!/usr/bin/expect
  • you ssh into a remote host, but you scp from your local machine. Is this what you intend?
    • if not, the 2nd spawn should be send instead.
    • I suspect this is the source of the scp "file not found" errors.
  • you use $2 instead of $ipaddress
  • if you don't intend to actually interact with the spawned process, wait for it to end with expect eof not interact
  • your shell script creates "script1.sh" and "script2.sh" but does not create "localscript.sh"
  • ".sh" is not a descriptive extension for expect code: ".exp" would be better
  • quote all shell variables: ./script1.sh "$password" "$2" "$timevalue"

I'd write that like this. Obviously untested:

#!/bin/bash
export password=$1
export ipaddress=$2
export timevalue=${3:--1}    # use default -1 if not specified\

[[ -z "$password" ]]  && { echo "Error: missing password";   exit 1; }
[[ -z "$ipaddress" ]] && { echo "Error: missing IP address"; exit 1; }

/usr/bin/expect -d <<END_EXPECT
    set timeout $env(timevalue)

    spawn sh -c "/usr/bin/ssh username@$env(ipaddress) /bin/bash < ./localscript.sh"
    expect "assword:"
    send "$env(password)\r"
    expect eof

    spawn /usr/bin/scp username@$env(ipaddress):"/path/from/source/*" /path/to/destination/folder/
    expect "assword:"
    send "$env(password)\r"
    expect eof
END_EXPECT

I added the -d option which turns on debug output for expect. Remove it when no longer needed.

The problem is that the spawn command does not know how to do the shell redirection: spawn is receiving the arguments "ssh", "user@host", "/bin/bash", "<" (a literal less-than), and "./localhost.sh". I'm explicitly executing that ssh command with a shell here so that the redirection can be done correctly.

  • Hi Glenn, Thank you for the response. -The Shebang is wrong because I was not aware of the coding indentations in this platform as the '#' was leading to a bigger format so I had to use two '#' in order to get the appropriate display. -I intend to ssh to a remote host to execute the script localscript.sh on that host and the output will be redirected to a file which will be pushed back to the local machine – user307080 Aug 23 '18 at 15:53
  • -The reason for scp "not found" error is because the folder from where the file has to copied is empty because the operations performed by the localscript.sh takes time to execute which was not provided by second spawn command - I am using $2 because my main script will have the argument of the ipaddress -I will try using eof instead of interact -localscript.sh is a part of the main programme which I have not shared in this post since this is just a snippet of the code where I see the issue. The rest of it works as expected. – user307080 Aug 23 '18 at 16:00
  • -Sure, I will work on the 'exp' and the quoted remarks mentioned and will let you know if that helps. Thank you so much for your inputs. – user307080 Aug 23 '18 at 16:01
  • Hi Glenn, Thank you so for the response. You were spot on with the inclusion of sh -c "/usr/bin/ssh username@$ipaddress /bin/bash < ./localscript.sh" This helped me in solving the first part of the puzzle and later, I added 'expect eof' instead of interact. The reason I was getting scp "not found" was because I was using quotes while specifying the path which was literally taking * as the filename. After the quotes were removed, I was able to get the desired output. It seems like this anomaly is seen while using spawn as the desired output was seen using quotes manually. – user307080 Aug 24 '18 at 14:18

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.