Reputation: 16186
I'm writing a script to remotely install linux software updates (which use a .bin updater tool) using Expect. I'm having trouble matching one block, and I've tried a bunch of variations with no success. I've gotten other similar scripts to work, but I've used wildcards to match newlines, and in this case, I need to make sure the list of files is exactly what I'm expecting, so I didn't want to break it up with any wildcards that could hide a mismatch.
Can someone take a look and tell me what I'm doing wrong?
Console output, plain
Checking for local modifications.
List of modifications made within Jira directories.
The following provides a list of file modifications within the
atlassian-jira directory.
Modified files:
atlassian-jira/WEB-INF/classes/seraph-config.xml
bin/setenv.sh
conf/server.xml
Removed files:
(none)
Added files:
atlassian-jira/WEB-INF/classes/crowd.properties
[Enter]
My latest attempt to match it and send Enter (line breaks only added to Stack Overflow, not present in script
expect {*Checking for local modifications*Modified files:\r\n\tatlassian-jira/WEB-INF/classes/seraph-config.xml\r\n\tbin/setenv.sh\r\n\tconf/server.xml\r\nRemoved files:\r\n\t(none)\r\nAdded files:\r\n\tatlassian-jira/WEB-INF/classes/crowd.properties\r\n\r\n\[Enter\]}
When I run through expect
with the -d
flag, this is what it prints:
expect: does "\r\nn\r\n\r\nChecking for local modifications.\r\n\r\nList of modifications made within Jira directories.\r\n\r\nThe following provides a list of file modifications within the\r\natlassian-jira directory.\r\n\r\nModified files:\r\n\tatlassian-jira/WEB-INF/classes/seraph-config.xml\r\n\tbin/setenv.sh\r\n\tconf/server.xml\r\nRemoved files:\r\n\t(none)\r\nAdded files:\r\n\tatlassian-jira/WEB-INF/classes/crowd.properties\r\n\r\n[Enter]\r\n" (spawn_id exp5) match glob pattern "*Checking for local modifications*Modified files:\r\n\tatlassian-jira/WEB-INF/classes/seraph-config.xml\r\n\tbin/setenv.sh\r\n\tconf/server.xml\r\nRemoved files:\r\n\t(none)\r\nAdded files:\r\n\tatlassian-jira/WEB-INF/classes/crowd.properties\r\n\r\n\[Enter\]"? no
I'm running from an outer bash script like so:
#!/usr/bin/env bash
set -e
sudo expect -d << EOD
spawn ${INSTALLER_PATH}
expect_before timeout { exit 1 }
expect {Match phrase} {
send -- "\r"
}
...
expect eof
EOD
** Update 4/5/2021 **
I tried @pynexj's suggestion to use ""
instead of {}
to surround my expression (below), it still doesn't work.
New script
sudo expect -d << EOD
...
expect "\r\nn\r\n\r\nChecking for local modifications.\r\n\r\nList of modifications made within Jira directories.\r\n\r\nThe following provides a list of file modifications within the\r\natlassian-jira directory.\r\n\r\nModified files:\r\n\tatlassian-jira/WEB-INF/classes/seraph-config.xml\r\n\tbin/setenv.sh\r\n\tconf/server.xml\r\nRemoved files:\r\n\t(none)\r\nAdded files:\r\n\tatlassian-jira/WEB-INF/classes/crowd.properties\r\n\r\n\[Enter\]\r\n" {
send -- "\r"
}
expect eof
EOD
I ran the debug output I received through Beyond Compare and the two strings printed out match each other 100%.
Updated debug output
expect: does "\r\nn\r\n\r\nChecking for local modifications.\r\n\r\nList of modifications made within Jira directories.\r\n\r\nThe following provides a list of file modifications within the\r\natlassian-jira directory.\r\n\r\nModified files:\r\n\tatlassian-jira/WEB-INF/classes/seraph-config.xml\r\n\tbin/setenv.sh\r\n\tconf/server.xml\r\nRemoved files:\r\n\t(none)\r\nAdded files:\r\n\tatlassian-jira/WEB-INF/classes/crowd.properties\r\n\r\n[Enter]\r\n" (spawn_id exp5) match glob pattern "\r\nn\r\n\r\nChecking for local modifications.\r\n\r\nList of modifications made within Jira directories.\r\n\r\nThe following provides a list of file modifications within the\r\natlassian-jira directory.\r\n\r\nModified files:\r\n\tatlassian-jira/WEB-INF/classes/seraph-config.xml\r\n\tbin/setenv.sh\r\n\tconf/server.xml\r\nRemoved files:\r\n\t(none)\r\nAdded files:\r\n\tatlassian-jira/WEB-INF/classes/crowd.properties\r\n\r\n[Enter]\r\n"? no
Two strings on top of each other
You can scroll these sideways in Stack Overflow to see they match 100%:
# command output on top
\r\nn\r\n\r\nChecking for local modifications.\r\n\r\nList of modifications made within Jira directories.\r\n\r\nThe following provides a list of file modifications within the\r\natlassian-jira directory.\r\n\r\nModified files:\r\n\tatlassian-jira/WEB-INF/classes/seraph-config.xml\r\n\tbin/setenv.sh\r\n\tconf/server.xml\r\nRemoved files:\r\n\t(none)\r\nAdded files:\r\n\tatlassian-jira/WEB-INF/classes/crowd.properties\r\n\r\n[Enter]\r\n
\r\nn\r\n\r\nChecking for local modifications.\r\n\r\nList of modifications made within Jira directories.\r\n\r\nThe following provides a list of file modifications within the\r\natlassian-jira directory.\r\n\r\nModified files:\r\n\tatlassian-jira/WEB-INF/classes/seraph-config.xml\r\n\tbin/setenv.sh\r\n\tconf/server.xml\r\nRemoved files:\r\n\t(none)\r\nAdded files:\r\n\tatlassian-jira/WEB-INF/classes/crowd.properties\r\n\r\n[Enter]\r\n
# Expect expression underneath
Upvotes: 1
Views: 511
Reputation: 20797
In Tcl, backslash escaped strings (like \r\n
) embedded in braces ({}
) has no special meaning. You should use double quotes here.
$ tclsh
% puts {foo\tbar\r\n}
foo\tbar\r\n
% puts "foo\tbar\r\n"
foo bar
%
According to Tcl doc:
[6] Braces.
If the first character of a word is an open brace (
{
) and rule [5] does not apply, then the word is terminated by the matching close brace (}
). Braces nest within the word: for each additional open brace there must be an additional close brace (however, if an open brace or close brace within the word is quoted with a backslash then it is not counted in locating the matching close brace). No substitutions are performed on the characters between the braces except for backslash-newline substitutions described below, nor do semi-colons, newlines, close brackets, or white space receive any special interpretation. The word will consist of exactly the characters between the outer braces, not including the braces themselves.
But note that when you use double quotes. To match [Enter]
you need to write \\\[Enetr\\\]
because by default the expect
statement uses glob-style matching. For example:
$ expect -c 'spawn -noecho bash -c {echo "[Enter]"}; expect eof'
[Enter]
$ expect -c 'spawn -noecho bash -c {echo "[Enter]"}; expect "\\\[Enter\\\]"; expect eof'
[Enter]
$ expect -c 'spawn -noecho bash -c {echo "[Enter]"}; expect -ex "\[Enter\]"; expect eof'
[Enter]
$
UPDATE:
Just noticed you are using Bash's here doc. Then you have to do one more level quoting.
$ expect << EOF
> spawn -noecho bash -c {echo "[Enter]"}
> expect "\\\\\\[Enter\\\\\\]"
> expect eof
> EOF
[Enter]
$
Or you can use << "QUOTED_STRING_HERE"
:
$ expect << 'EOF'
> spawn -noecho bash -c {echo "[Enter]"}
> expect "\\\[Enter\\\]"
> expect eof
> EOF
[Enter]
$
According to man bash
, for << word
:
If any part of word is quoted, the delimiter is the result of quote removal on word, and the lines in the here-document are not expanded.
Upvotes: 2
Reputation: 16186
I needed to make two changes to get it to match:
""
instead of {}
This is what I ended up with, making it as readable as possible:
sudo expect << EOD
spawn ${INSTALLER_PATH}
...
expect {*Back up Jira home directory?*Yes \[y\], No \[n, Enter\]} {
send -- "n\r"
}
expect -ex "\r\n\
n\r\n\
\r\n\
Checking for local modifications.\r\n\
\r\n\
List of modifications made within Jira directories.\r\n\
\r\n\
The following provides a list of file modifications within the\r\n\
atlassian-jira directory.\r\n\
\r\n\
Modified files:\r\n\
atlassian-jira/WEB-INF/classes/seraph-config.xml\r\n\
bin/setenv.sh\r\n\
conf/server.xml\r\n\
Removed files:\r\n\
(none)\r\n\
Added files:\r\n\
atlassian-jira/WEB-INF/classes/crowd.properties\r\n\
\r\n\
\[Enter\]\r\n\
" {
send -- "\r"
}
expect eof
EOD
Upvotes: 0