Shell scripting : Giving error invalid command name "server1" - shell

I have written a shell script for double authentication.
This is giving an error while execution in if statement.
#!/usr/bin/Expect
#!/bin/bash
set cpPass "App12345"
set server [lindex $argv 0]
set pass "App12345#123"
set app "app1"
set appPass "app#1013"
spawn ssh user1#$server.corp.clll.com
expect {
"(yes/no)?" {
send "yes\r"
expect "password:"
send "$cpPass\r"
}
"password:" {
send "$pass\r"
}
}
expect "bash"
send "su - $app\r"
expect "Password:"
send "$appPass\r"
if [ "$server" == "server1" ]
then
send "cd /ngs/app/genevad/QA/site/distribution/servers1\r";
else
send "sqlplus gqa_owner/App#789#dbgeneva01d.corp.clll.com:1700/app1D\r";
fi
interact
The error is like this on execution of command
./script.sh server1
invalid command name "server1"
while executing
""$server" == "novello" "
invoked from within
"if [ "$server" == "novello" ]"
(file "./script.sh" line 28)
I have tried various combinations in if like :
if [ $server == "novello" ]
if [ $server -eq "novello" ]
if [ "$server" -eq "novello" ]
etc but still not working. Any suggestions/Solutions to it?

Problem is here:
#!/usr/bin/Expect
#!/bin/bash
You cannot have 2 shebangs in same Unix script. Only first will be in effect and second will be ignored. Hence your script must be fully expect compliant script (since that is first one here - should be lowercase expect though).
Moment you try to use a bash syntax in it, you will get errors since that bash specific script will be interpreted by expect.

Replace the code [$server == "server1"] with {$server == "server1"}. As anubhava pointed out, u don't need 2 executeables name in the shebang. You can use only bash. Include all your expect code with -c flag. To know more about how to use expect with -c flag, have a look at https://stackoverflow.com/a/26607110/974155

Related

How to set variable value inside the remote server

Inside the remote server i have a condition statement.If that condition passes
status value should be set as success.
But here i am always getting Failure response while i print status variable
status='Success';
status='Success';
# !/bin/bash
declare -a server_PP=('XXXXX' 'YYYYYYY' );
declare -A results_map;
function process(){
serverList=$1[#];
servers=("${!serverList}");
status='Failure';
for serverName in "${servers[#]}"
do
ssh $serverName << EOF
if [ -f /app/Release/abc.war ]; then
echo "available - success"
status='Success';
fi
echo "***********status-inside******$status"
exit
EOF
echo "***********status-outside******$status"
results_map+=([$serverName]=$status);
done
}
process 'server_PP'
for i in "${!results_map[#]}"
do
echo "key :" $i
echo "value:" ${results_map[$i]}
done
Status variable should set as success when that condition get satisfied.
As written in pcarter's comment, the variables on both systems are independent from each other and don't get passed via ssh. Instead of setting a variable (or printing and reading the value as proposed in the comment, which is a working solution) you can use the exit code which gets passed automatically by ssh.
The following script is close to the original. For further improvements see below.
# !/bin/bash
declare -a server_PP=('XXXXX' 'YYYYYYY' );
declare -A results_map;
function process(){
serverList=$1[#];
servers=("${!serverList}");
status='Failure';
for serverName in "${servers[#]}"
do
if ssh $serverName << EOF
if [ -f /app/Release/abc.war ]; then
echo "available - success"
exit 0;
fi
echo "error"
exit 1
EOF
then
status='Success'
else
status='Failure'
fi
echo "***********status-outside******$status"
results_map+=([$serverName]=$status);
done
}
process 'server_PP'
for i in "${!results_map[#]}"
do
echo "key :" $i
echo "value:" ${results_map[$i]}
done
As you no longer need the variable assignments you can even omit the if ... and exit in the remote commands.
if ssh $serverName << EOF
[ -f /app/Release/abc.war ]
EOF
then
...
Your approach of using a heredoc as
ssh hostname <<EOF
# commands ...
EOF
has the disadvantage that you run an interactive shell on the remote system, which may print some system information or welcome message before executing your commands. You can further simplify the script (and removing the welcome message) by specifying the command or a script as command line arguments for ssh.
if ssh $serverName [ -f /app/Release/abc.war ]
then
...
If your command sequence is longer you can create a script on the remote system and run this script in the same way as ssh hostname scriptname. You could also create the script on the remote system using ssh or scp.

expect statement in bash script for error validation of expected output

I have the following expect statement within my bash script:
/usr/bin/expect << EOF
spawn -noecho lucli users add -username user -role admin -email
user#user.com
expect "password:" { send "password\n" }
expect "password:" { send "password\n" }
expect eof
EOF
I want the expect script to validate that the correct output is returned from the CLI command after it passes the passwords and creates the user.
The message I want to validate that gets returned is "added to the system successfully"
I can't figure out how to do that from within the bash script using expect.
Can anyone help?
You could try something like this:
# note the quoted here-doc word
status=$(/usr/bin/expect << 'EOF'
spawn -noecho lucli users add -username user -role admin -email
user#user.com
expect "password:" { send "password\r" }
expect "password:" { send "password\r" }
expect eof
set status [string match "*added to the system successfully*" $expect_out(buffer)]
# $status will be the C-like boolean 0 or 1
exit $status
EOF
)
if [[ $status -eq 1 ]]; then
echo "user added OK"
else
echo "user not added"
fi
ref: https://tcl.tk/man/tcl8.6/TclCmd/string.htm

How to validate number of input parameters in an expect shell script?

I'm trying to validate the number of arguments in a shell script I'm creating.
The script will be using expect.
Error
invalid command name "$#"
while executing
"$# -ne 3 "
invoked from within
"if [ $# -ne 3 ] then"
Script:
#!/usr/bin/expect -f
if [ $# -ne 3 ] then
echo "Wrong number of arguments provided"
echo "fgrep_host.sh hostname filter_text new_file"
exit
fi
As #Dinesh said, an expect script is not a shell script, it's an expect script, which is Tcl.
To do what you want, you'd write it:
#!/usr/bin/expect -f
if {$argc != 3} {
puts "Wrong number of arguments provided"
puts "fgrep_host.sh hostname filter_text new_file"
exit 1
}
(though you shouldn't be adding the .sh extension)
You're going to have to read up on expect and Tcl to continue.

using set and expect in shell script

I am trying to ssh into few systems (read from test.txt file) using expect within a shell script and execute commands on each. The script returns an error "invalid command name". Am I using set and expect in an incorrect way here?
#!/usr/bin/expect -f
set username "root"
set pass "mypassword"
set fd [open /home/test.txt r]
set host [read $fd]
foreach line $host {
ssh -o StrictHostKeyChecking=no -n root#$host 'ls; pwd'
expect "User:" { send "${username}\r" }
expect "root's Password:" { send "${pass}\r" }
expect eof
}
Error returned
./expect.sh
spawn ssh -o StrictHostKeyChecking=no -n root#10.1.1.1
10.1.1.2
'ls
invalid command name "pwd'"
while executing
"pwd' "
("foreach" body line 3)
invoked from within
"foreach line $host {
As the error message suggests, expect parsed ; as a command separator, and couldn't handle pwd'.
That's because there are no single-quoted strings in the language.
Expect is tcl, you have to use double quotes: "ls; pwd"

expect inside bash + wrong # args: should be "foreach varList list ?varList list ...? command"

I am using expect script inside bash script. When I use foreach inside expect script, it throws
wrong # args: should be "foreach varList list ?varList list ...? command"
The code:
#!/bin/bash
read -p "Enter username: " username
read -s -p "Enter password: " password
#Expect script
/bin/expect -<<EOD
set SERVERS {100 101 102}
foreach SERVER $SERVERS {
set timeout -1
spawn scp ${username}#plsa${SERVER}.corp.com:/log.2011-11-24 ${SERVER}
expect "*password:"; send "$password\r"
expect eof }
EOD
echo "completed"
Thanks
The heredoc (<<ENDTOK) is subject to shell expansion on the $variables. That means for each of the $variables you want expect to interpret, you'll need to escape the $.
The way to escape something is to prepend a slash to it ($ -> \$).
It appears the username and password are supposed to come from the shell, the rest from within expect, so here's how that should go:
#!/bin/bash
read -p "Enter username: " username
read -s -p "Enter password: " password
#Expect script
/bin/expect -<<EOD
set SERVERS {100 101 102}
foreach SERVER \$SERVERS {
set timeout -1
spawn scp ${username}#plsa\${SERVER}.corp.com:/log.2011-11-24 \${SERVER}
expect "*password:"; send "$password\r"
expect eof }
EOD
echo "completed"
Note the \ in front of $SERVERS and ${SERVER}.
You need to escape dollar signs with a backslash since $name is expended to the value of variable name:
/bin/expect -<<EOD
set SERVERS {100 101 102}
foreach SERVER \$SERVERS {
set timeout -1
spawn scp ${username}#plsa\${SERVER}.corp.com:/log.2011-11-24 \${SERVER}
expect "*password:"; send "$password\r"
expect eof }
EOD
If you quote your here-document delimiter, the embedded script is effectively quoted too:
/bin/expect -<<'EOD'
... expect script as posted ...
EOD

Resources