Want to use double quote inside a double quote - shell

#!/opt/sfw/bin/expect --
spawn telnet -e ! [lindex $argv 0]
expect "<"
send "ACT-USER::ABCDEFG:123::\"ABCD\";"
Above is not working giving error due to double quote inside a double quote
Error:
spawn telnet -e !
Telnet escape character is '!'.
invalid flags
send: spawn id exp7 not open
while executing
"send "ACT-USER::ABCDEFG:123::'\"ABCD\"';""
(file "./get-amp-pms.sh" line 4)

Use curly braces instead of the double quotes for the send, as follows:
send {ACT-USER::ABCDEFG:123::"ABCD";}

The error is unrelated to the double-quoting; the spawned process is exiting on an error before the command string is being sent.
expect is tcl, so tcl quoting mechanisms work. Sending a string with double quotes can be done by escaping the quoted with backslashes, or using braces:
send "message with \"double quotes\""
send {message with "double quotes"}

Not sure But we can use single quote in few commands like(sed) to overcome this issue and freely use double quote inside single quote without hampering the functionality.So try using the parameters enclosed in single quote(Example : send 'paramters' )to execute it

Related

Why would I want to wrap my script commands in double quotes?

I'm working through Red Hat Academy and one of the sample scripts provided differed from mine in a key way that I haven't been able to understand:
#!/usr/bin/bash
#
USR='student'
OUT='/home/student/output'
#
for SRV in servera serverb
do
ssh ${USR}#${SRV} "hostname -f" > ${OUT}-${SRV}
echo "#####" >> ${OUT}-${SRV}
ssh ${USR}#${SRV} "lscpu | grep '^CPU'" >> ${OUT}-${SRV}
echo "#####" >> ${OUT}-${SRV}
ssh ${USR}#${SRV} "grep -v '^$' /etc/selinux/config|grep -v '^#'" >> ${OUT}-${SRV}
echo "#####" >> ${OUT}-${SRV}
ssh ${USR}#${SRV} "sudo grep 'Failed password' /var/log/secure" >> ${OUT}-${SRV}
echo "#####" >> ${OUT}-${SRV}
done
On each line after the variable expansion, they've wrapped most of the rest of the command in double quotes. Now, I understand the usage of double quotes and single quotes when it comes to suppressing expansion/substitution, but the main takeaway I've learned is straight from the RH Academy:
It is recommended practice to use single quotation marks to
encapsulate the regular expression to protect any shell metacharacters
(such as the $, *, and {} characters). Encapsulating the regular
expression ensures that the characters are interpreted by the intended
command and not by the shell.
I can see that they're doing that here to make sure the regular expressions are properly passed to grep in a couple of lines, but I can't figure out the purpose of the double quotes. My questions are:
Why are they there?
Why are they only wrapped around a portion of
each line?
Is this a common practice?
As pointed out by others, the example provided has issues of being malformed for the intended purpose. Specifically, the 3rd ssh requires the "$" in '^$' to be escaped, to avoid the shell's attempt at substitution at your end. Otherwise, the remote host will see '^' !!!
Their usage of double-quotes is intended to "encapsulate" a construct meant to be executed as is on the remote server, hence around everything after the target host reference.
Issues arise if you need to expand variable values before sending to remote ... AND ... when you need such expansion to NOT occur. Single-quotes are meant to contain literals meant to be passed as-is, but if that is contained within another set of double-quotes, the contents of those are not "protected" and the shell attempts the usual substitutions whenever "$" is encountered.
For simple constructs, one-line commands are OK.
BUT ... when things get more complex (with multiple levels of "\" for escaping single-/double-quotes), it might be best to create a job-script, massage that into what is required for the remote host before calling ssh, then have ssh reference that in the following manner:
ssh user#remote 'bash -s' < local_script.sh
As for the line doing the check for failed password, I would never leave that to the end. I would have that as the first line, check the output, and abandon if the password failed, avoiding the likely failed attempts for the other commands, which at that point serves no purpose.

Expect does not detect string

I need to automate the input of a string in a command called from a shell (sh) script, using expect To accomplish this I have:
#!/bin/sh
MY_ARGS="-a -b -c" expect -c "
spawn mycommand $MY_ARGS
expect 'continue, I know what I am doing' { send -- 'continue, I know what I am doing\r' }
expect eof"
The mycommand output is:
Enter "continue, I know what I am doing" to use the outdated data anyway:
But the string is not being detected and therefore nothing is sent. What is wrong with the expect command?
Thanks.
There's a few things going on here:
When you write var=value some_command, then $var is set in the environment for the command.
Inside expect you need $env(MY_ARGS)
But now you have a quoting problem, you can't put the expect body in double quotes because you
don't want the shell to expand that variable.
#sexpect_Expect.for.Shells is right, single quotes are not special in Tcl (and hence expect). expect sees this:
expect {
{'continue,} {I}
{know} {what}
{I} {am}
{doing'} { send -- "'continue," "I" "know" "what" "I" "am" "doing\r'" }
}
To solve the quoting problems, I recommand using a quoted heredoc in the shell
export MY_ARGS='-a -b -c'
# .......v..........v these quotes are crucial
expect <<'END_EXPECT'
set phrase "continue, I know what I am doing"
set timeout -1
spawn mycommand {*}$env(MY_ARGS)
expect $phrase
send -- "$phrase\r"
expect eof
END_EXPECT
Note how I expanded the env variable: {*}$env(MY_ARGS) -- the {*} syntax splits the variable content into separate words.

Can't run an expect script: invalid command name "Yes/No"

I have this expect script that need to execute some other shell script to accept a Licence agreement
#!/usr/bin/expect
spawn ./xxx.sh
expect -ex "--More--"
send -- " "
expect "Do you agree with this license ?[Yes/No]"
send "Y\r"
But when I run it I get this error
invalid command name "Yes/No"
while executing
"Yes/No"
invoked from within
"expect "Do you agree with this license ?[Yes/No]""
(file "./xxx.sh" line 5)
I don't know what I'm doing wrong
expect is an extension of the Tcl language. In Tcl, you use square brackets for command substitution. Like the bash shell, command substitution occurs within double quoted strings.
To prevent your code from attempting to execute the Yes/No command:
use different quotes: Tcl uses curly braces as the non-interpolating quotes:
expect {Do you agree with this license ?[Yes/No]}
escape the brackets to prevent command substitution:
expect "Do you agree with this license ?\[Yes/No\]"

Expect script not working and send status getting skipped

I have written a script to execute a setup on the server, but while executing send statement is getting skipped and other one getting executed.
Below is my script :
enter code here[code written][1]
====================ERROR m getting=============================
Enter the name of the new namespace you want to create [coe_ns] :
Enter the name of the clearinghouse you want to create [coe_ch] : invalid command name "C"
while executing
"C"
invoked from within
"expect -re "* Option to execute (Continue/Restart/Quit) [C]: $""
(file "./TNS_Server_Setup.sh" line 21)
I have a doubt that send command before that is not getting executed, also am I passing "ENTER" right way.
expect uses square brackets as the command substitution syntax (in the same way that the shell uses backticks or $(...). So when you write
expect -re "* Option to execute (Continue/Restart/Quit) [C]: $"
expect sees [C] and tries to invoke the command C.
Also, that standalone * will throw a "quantifier operand invalid" error, because that's a special character for regular expressions. You either need to escape it or remove it from the expression.
Use a different quoting mechanism that inhibits command substitution (like in the shell where you'd use single quotes)
expect -re {Option to execute (Continue/Restart/Quit) [C]: $}
You did not include your code in the question so we can't see your send command, but to "just hit enter", you would send "\r"
Update:
If you need to match multiple things, the expect command can do that: give it a list of pattern action pairs. Expect will match any of them.
expect {
-re {Option to execute (Continue/Restart/Quit) [C]: $} {
send "\r"
exp_continue
}
-re {enter the datatype $} {
send "array\r"
exp_continue
}
"some pattern that denotes we're done"
}

capture expect ssh output to variable

Hey am new to bash scripts and was wondering how would I capture the output of the ssh command into a bash variable? I looked around and cant seem to get it right. I have tried puts $expect_out(buffer) but when echo it says variable does not exist
I know the response should be just one line and if I want to save that into a variable response and then echo it how would I do that?
A generic idea can be something like as below.
spawn the ssh session
make proper login
Send each commands with send
Wait for desired output with expect
Example:
spawn ssh $user#$domain
expect "password" { send "$pwd\r"}
expect "#"; # This '#' is nothing but the terminal prompt
send "$cmd\r"
expect "#"
puts $expect_out(buffer); #Will print the output of the 'cmd' output now.
The word to wait for after executing the command can vary based on your system. It can be # or $ or > or :; So, make sure you are giving the correct one. Or, you can provide a generalized pattern for the prompt as such
set prompt "#|>|:|\\\$"; # We escaped the `$` symbol with backslash to match literal '$'
While using the expect after sending the commands, it can be used as
expect -re $prompt; #Using regex to match the pattern`

Resources