2

Setup Ubuntu 16.04 expect Scripts

In the simple script bellow the goal is to simply find the oldest .zip file in a directory on a remote machine using ssh.
Then use scp to download this file to the local "workingBuild" directory.

Current Script

#!/usr/bin/expect
set user "hidden"
set pass "hidden"
set sourceDir "/opt/tomcat/someDirectoryName/"
set workingDir "/home/someUser/workingBuild"

spawn sh -c "ssh $user@www ls -t $sourceDir | head -1"
expect "password:"
send "$pass\r"
expect -re ".*\.zip"

set sourceFile $expect_out(0,string)
spawn sh -c "echo 'bob'$sourceFile'bob2'"

spawn sh -c "scp $user@www:$sourceDir$sourceFile $workingDir"
expect {
        password: {send "$pass\r"; exp_continue}
}

Problem

It seems I'm getting a hidden carriage return (\r) populated into my $sourceFile variable at the Front of the file name stored. This in turn is causing problem in the scp command because it puts the filename and destinationDirectory on a new line like such. Causing an invalid command:

spawn sh -c scp meliudaj@www:/opt/tomcat/someDirectoryName/
build_0.0.1.zip /home/meliudaj/workingBuild

This is also demonstrated with the following debugging line in the above code:

spawn sh -c "echo 'bob'$sourceFile'bob2'"

$sourceFile'bob2' are always on a new line below 'bob'

The desired result would be as such:

spawn sh -c scp meliudaj@www:/opt/tomcat/someDirectoryName/ build_0.0.1.zip /home/meliudaj/workingBuild

Question

How can I either Remove the \r from the $sourceFile variable, or how can I populate the $sourceFile variable differently to prevent the (\r) from ever appearing in the first place.

P.S. I have tried a number of different attempts at using sed, awk, & tr But nothing I have tried seems to help.

DarbyM
  • 123

1 Answers1

3

After you send your password and "hit enter", the first thing ssh does is emit a newline. You're not accounting for this in the text you extract from the expect_out buffer. Also note that expect uses CRNL to represent a newline, which I understand is to align with some network procotol standards.

This interactive expect session pretty much reproduces the problem. At the end I'm sending the contents of the variable to the external command od to see exactly what's in it:

expect1.1> spawn sh -c {read password; ls -t | head -1}
spawn sh -c read password; ls -t | head -1
42945
expect1.2> send "\r"
expect1.3> expect "*.zip"

somefile.zip
expect1.4> set sourceFile $expect_out(0,string)

somefile.zip
expect1.5> exec od -c << $sourceFile
0000000  \r  \n   s   o   m   e   f   i   l   e   .   z   i   p
0000016

What you want to do is capture the text, ending with ".zip", that occurs after the last newline. Fairly straightforward to do with a regular expression:

expect1.1> spawn sh -c {read password; ls -t | head -1}
spawn sh -c read password; ls -t | head -1
42992
expect1.2> send "\r"
expect1.3> expect -re {.*\r\n(.*\.zip)}

somefile.zip
expect1.4> set sourceFile $expect_out(1,string)
somefile.zip
expect1.5> exec od -c << $sourceFile
0000000   s   o   m   e   f   i   l   e   .   z   i   p
0000014

Note the use of (1,string) to take the text captured by the first set of parentheses.

glenn jackman
  • 85,964
  • THIS was the piece I was missing. expect1.3> expect -re {.\r\n(..zip)} (RegEx is not my strong suit) Everything else was a correct explanation of what I was dealing with – DarbyM Jun 13 '19 at 01:56
  • 1
    I'd encourage you to spend some time studying it. Regex is an indispensable tool to have in your toolbox. – glenn jackman Jun 13 '19 at 03:04
  • 20 years working in different flavors of unix. I couldn't agree more, but RegEx just doesn't pop with me. Always having to break out the googlefoo and relearn it just to makes something work. I'll stick with my DBs :) – DarbyM Jun 13 '19 at 03:17