Capturing output of an expect session with a bash script - bash

I have a bash script that is using xmlstarlet to manipulate some key/value pairs in an application configuration file to prepare the file to be moved to a new production host. The values that need changed are host/encryption specific.
In order to discover one of the new values I need to interact with a vendor provided script in an expect session and capture the output into a variable in the bash script so I can continue to use it.
The expect part of the bash script looks something like this:
expect <<DONE
spawn command_provided_by_vendor
expect :
send -- "newvalue\r"
DONE
This is where I get stuck
In a shell the output of this command looks like:
Encrypted value (case sensitive, please cut and paste): 2qIrRvcSoHMb55dpcef6vw==
What I need to do is capture the non-whitespace output after the ":" and nothing I've tried works due to regexp errors, the parenthesis in the prompt string, etc.
There are other questions on stackoverflow that are similar, but I failed to understand how those answers helped my problem.
Any help, pointers appreciated.

I would use the expect command to look for an appropriate regular expression and capture the value there:
value=$(
expect <<DONE
spawn command_provided_by_vendor
expect :
send -- "newvalue\r"
expect -re {Encrypted value.*: (\S+)}
puts $expect_out(1,string)
expect eof
DONE
)

Related

Output of complete script to variable

I have rather complex bash script which is normally run manually and thus needs live output on the console (stdout and stderr).
However, since the outcome and output of this script is rather important I'd like to save its output at the end into a database.
I have already a trap function for this and the database query as such is also not a problem. The problem is: How do I get the output of the entire script till that point into a variable?
The live console output should be preserved. The output after the database query (if any) does not matter.
Is this possible at all? Might it be necessary to wrap the script into another script (file)?
I'm doing similar task like this
exec 5>&1
message=$(check|tee /dev/fd/5)
mutt -s "$subjct" "$mailto" <<< "$message"
Add your script instead of check function and change mailing to db query.

Return results for Ubuntu Updates in a Variable

I am trying to get the result from /usr/lib/update-notifier/apt-check on a Ubuntu 16 Server into a Array to make a XML response for a monitoring tool, but somehow the value of this apt-check just refuses to get in my Variable. For simplicity sake, I have omitted the XML creation part.
#!/bin/bash
APTCHECK="/usr/lib/update-notifier/apt-check"
APTResult="$(${APTCHECK})"
echo "Result is $APTResult"
exit 0
if you now run this code with bash -x you will see that the result is returned to the Terminal, but not assigned to the Variable. If I substitute the "command" to something simple like "ls -lah" everything works fine.
I just don't know why this is not working ? Anybody ?
apt-check prints to the stderr, so you need to capture that instead with aptresult=$(/usr/lib/update-notifier/apt-check 2>&1).
The other option is with the --human-readable switch, which'll print to the stdout. The only problem then is that you have to parse the text output (unless the text output is what you actually want).

grep Ipaddress in expect script

I want to grep ipaddress from file and set it to variable in expect scritp
send -- "cat $filename |grep ([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\})\r"
expect -re "([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}) *$prompt$"
set IP $expect_out(1,string)
but I'm not suceeding. Any idea? I'm using /usr/local/bin/expect. Thanks
From a quick scan, it seems to me you're trying to match a double prompt in your statement. You seem to have a variable followed by a literal prompt at the end of your expect regexp. Are you sure that is what you want?
Aside from that, I strongly recommend that you put expect_internal 1 somewhere at the top of your script, and that way expect will log output showing you what it is (and is not) matching. You really shouldn't be trying to debug regexp matching without it, it's like searching in the dark...

Ignore Bash Trace in expect

I am try to write regression tests using expect for an interactive bash script.
So far everything works Ok. I spawn the process with the correct arguments, and then send/expect.
I would like, during tests, to enable tracing in the bash script, using the set -x command. However, when doing so, the bash trace output messes with expect.
I would like expect to ignore those lines when performing matching but still output them on either stdout or stderr.
Apperently, there is so way to treat stderr and stdout independently.
I have already tried a few thing using expect_before and expect_background, but none having given me good results.
Any thoughts ?
Thanks.
If the output (I mean non-trace output) from your bash script if well-defined, you can simply ignore the trace output when using expect command. For example, if your script shows:
+ echo 'Password:'
Password:
you can use regexp mode of expect:
expect -re '^Password:'
That would ignore the trace output but match the password prompt. Granted, your match rules should be very tight to not match any undesirable output.

How can I flush the input buffer in an expect script?

I'm writing an Expect script and am having trouble dealing with the shell prompt (on Linux). My Expect script spawns rlogin and the remote system is using ksh. The prompt on the remote system contains the current directory followed by " > " (space greater-than space). A script snippet might be:
send "some command here\r"
expect " > "
This works for simple commands, but things start to go wrong when the command I'm sending exceeds the width of the terminal (or more precisely, what ksh thinks is the width of the terminal). In that case, ksh does some weird horizontal scrolling of the interactive command line, which seems to rewrite the prompt and stick an extra " > " in the output. Naturally this causes the Expect script to get confused and out of sync when there appears to be more than one prompt in the output after executing a command (my script contains several send/expect pairs).
I've tried changing PS1 on the remote system to something more distinctive like "prompt> " but a similar problem arises which indicates to me that's not the right way to solve this.
What I'm thinking might help is the ability for the script to tell Expect that "I know I'm properly synchronised with the remote system at this point, so flush the input buffer now." The expect statement has the -notransfer flag which doesn't discard the input buffer even if the pattern does match, so I think I need the opposite of that.
Are there any other useful techniques that I can use to make the remote shell behave more predictably? I understand that Expect goes through a lot of work to make sure that the spawned session appears to be interactive to the remote system, but I'd rather that some of the more annoying interactive features (such as the horizontal scrolling of ksh) be turned off.
If you want to throw away all output Expect has seen so far, try
expect -re $
This is a regexp match on $ which means the end of the input buffer, so it will just skip everything received so far. More details at the Expect man page.
You could try "set -o multiline" or COLUMNS=1000000 (or some other suitably large value).
I have had difficulty with ksh and Expect in the past. My solution was to use something other than
ksh for a login shell.
If you can change the remote login to other than ksh (using the chsh command or editing /etc/passwd) then you might try this with /bin/sh as the shell.
Another alternative is to tell KSH that the terminal is a dumb terminal - disallow it from doing any special processing.
$ export TERM=""
might do the trick.

Resources