Below is my script:
#!/usr/bin/expect
echo "enter unique id"
read test
mkdir -p /evoting_test/$test
spawn scp -r abc#10.150.10.104:/shareddata/was/l1/*.pdf /rishabh/$test/
set pass "abc123"
expect {
password: {send "$pass\r"; exp_continue}
}
I am getting error:
invalid command name "echo"
while executing
"echo "enter uNIQUE id" "
(file "./scp_test.sh" line 2)
It is not reading variable from user and use that variable in command
The "expect" way to do that is:
send_user "enter unique id: "
expect_user -re "(.*)\n"
set test $expect_out(1,string)
send_user "you said $test\n"
Since expect extends tcl, you could use:
puts -nonewline "enter unique id: "
flush stdout
gets stdin test
puts "you said $test"
Additionally, you'll get an error for mkdir -- that's an external command. You can do one of:
exec mkdir -p /evoting_test/$test # invoke the external command
file mkdir /evoting_test/$test # use the builtin
See http://tcl.tk/man/tcl8.6/TclCmd/file.htm
IMHO the best way to solve this out would be to separate the two files each of which is using a different interpreter as per its requirement.
First File: will contain the code to scp all the pdf files to the desired location and you can read the destination location in this script as well.
Use expect to run the above file and get your work done.
Related
I have a list of 400 servers and I like to check unix account existence with expect to loop it
I wrote a bash script that uses expect command but it returns me error message that I don't understand the meaning
#!/bin/bash
fic_serv="test.txt"
echo "Passwd"
stty -echo
read -s passwd
stty echo
suffix="suffix"
account="acc"
for server in `cat $fic_serv`
do
prompt="[$acc#$server ~]$ "
expect -c "
spawn ssh -o StrictHostKeyChecking=no $account#$server.$suffix
expect "Password: "
send "$passwd\r"
expect $prompt
send "logout\r"
"
done
[acc#serv ~]$ couldn't read file "
send "passwd\r"
expect [acc#server ~]$
send "logout\r"
": no such file or directory
(I modified the value)
You should use while, not for, to parse files in Bash. Use a "redirect" to treat a file as standard input and read one line at a time.
while read server; do
...
done < $fic_serv
Your major problem is Expect interprets your "s as "end of script". Escape them, as in \", or use {}, as in:
expect -c "
spawn ssh -o StrictHostKeyChecking=no $account#$server.$suffix
expect {Password: }
send {$passwd\r}
expect $prompt
send {logout\r}
"
If you have 400 servers to manage, I strongly recommend you use ansible.
You could just put the list of hosts into a file, let's call it inventory, and run the following command:
ansible -i inventory -m shell -a "id acc" all
Using here-docs in the shell to embed code for another language is usually better than quoting hell, and sharing variables through the environment is easier and safer than parameter expansion:
export account passwd
while IFS= read -r server; do
export prompt="[$acc#$server ~]$ "
export host="$server.$suffix"
expect << 'END_EXPECT'
spawn ssh -o StrictHostKeyChecking=no $env(account)#$env(host)
expect "Password: "
send "$env(passwd)\r"
expect $env(prompt)
send "logout\r"
expect eof
END_EXPECT
done < "$fic_serv"
As shown, I like to indent the heredoc to make it more obvious.
And depending on the error message or login prompt, there can be more logic to indicate that the account name and/or password are incorrect.
I am often in the need of running a bash script that needs inputs from me and im trying to improve my workflow by automating this.
In my case my bash script is in need of 3 inputs from me:
What interface should i use?
1
Enter the password:
mypass
Please restart the program:
sudo bash restart
How can i make my bash script file auto input theses values? I have tried figuring this out but all the answer are about inputing yes or no.
If that is all the input your program needs, then you can simply put the inputs, one per line, in a text file, then run it like this:
$> ./yourscript.sh < yourtextfile.txt
For your example, the text file would contain
1
mypass
sudo bash restart
If you have such a script.sh:
#!/bin/bash
read -p "What intergace should i use?"$'\n' interfacenum
echo
read -p "Enter the password:"$'\n' pass
echo
read -p "Please restaart the program:"$'\n' prog
echo
echo "Values:"
for i in interfacenum pass prog; do
echo $'\t'"$i=\"${!i}\""
done
You can 'input' the values into the script using echo or printf:
echo -ne "1\nmypass\nsudo bash restart\n" | ./script.sh
You can use expect and autoexpect to achieve your task.
Let's say this is your file:
cat hello.sh
#!/usr/local/bin/bash
read -p "Select the interface: " interface
echo "interface selected: $interface"
read -p "Enter the username: " username
echo "username: $username"
You don't have to even write the scripts. You can you autoexpect to generate the script for you.
autoexpect ./hello.sh
autoexpect started, file is script.exp
Select the interface: 1
interface selected: 1
...(more input and output to generate the script)
Examine the generated script.
tail -n7 script.exp
expect -exact "Select the interface: "
send -- "1\r"
expect -exact "1\r
interface selected: 1\r
Enter the username: "
send -- "vivek\r"
expect eof
Now sit back and run the generated script
./script.exp
spawn ./hello.sh
Select the interface: 1
interface selected: 1
Enter the username: vivek
username: vivek
I am attempting to write a script that greps for something in a number of servers and appends the output of all of them into a single file. The servers are password protected. I use expect to enter the servers and pass the grep command but I am hoping to get the output of each of them to end up in a single file.
Here is an overview of what I want to do:
spawn ssh xxx#server1
expect "password: "
send "PASSWORD\r"
expect "$ "
send "grep <something> /some/log/file >> file.txt"
expect "$ "
send "exit\r"
... then continue doing this in dozens more servers with the output of the grep command appending to file.txt each time. I don't mind where the file.txt actually is. It can be on my local computer or any of the servers.
The best I've come up with would be to put each of these in a file on the server the grep is being done on and then scp all those files to local and appending them all. This seems incredibly wasteful though, so I am looking for a way to send the output to a server or to local from a server.
It would be both easier to automate and more secure if you used public key authentication instead of password authentication to get to the servers. Then you could simply loop over them like this:
for host in server1 server2 server3 ...; do
ssh -n "$host" 'grep <something> /some/log/file'
done >file.txt
Since you have password access, you can easily put a public key in .ssh/authorized_keys to enable key access first. You can do it with your expect script:
spawn ssh xxx#server1
expect "password: "
send "PASSWORD\r"
expect "$ "
send "mkdir -p .ssh\r"
expect "$ "
send "cat >>.ssh/authorized_keys <<EOF"
send "(public key goes here)\r"
send "EOF\r"
expect "$ "
send "chmod 0700 .ssh\r"
expect "$ "
send "chmod 0600 .ssh/authorized_keys\r"
expect "$ "
send "exit\r"
If for some reason you must use a solution with password-entry, you can append to a file with expect with something like:
log_user 0 # to not see the output on screen
set fh [open foo.log a] # open the file for appending
set servers {user#server user#server2 […]}
foreach s $servers {
spawn ssh user#server
[…]
send "command"
expect "$ " { puts $fh "$expect_out(buffer)"}
}
close $fh
i am writing code to automate some steps . First it is required to switch user and then run a perl script. Here is my code
if [ -a /try/Test ]
then
su trial -c ". /try/.profile Test"
expect -c 'spawn try1;
send "3\r";
send "1\r";
send "show\r";
interact';
fi
try1 is my perl program which i am trying to call.This script throws this error
couldn't execute "try1": no such file or directory
while executing
"spawn try1"
but once i do this step manually and then run this script then this script runs without nay error.
I think you've already asked about it (and I did answer, didn't I)?
Here's the basic skeleton (make sure to add error/timeout/unexpected output handling):
# collect password
stty -echo
send_user -- "Password: "
expect_user -re "(.*)\n"
send_user "\n"
stty echo
set pass $expect_out(1,string)
spawn sudo sh;
expect -re ": *$";
send -- "$pass\r"
expect -re "\$ *$";
send "echo SETTING PARAMS\r";
expect -re "\$ *$";
send "echo RUNNING MY COMMAND\r";
expect -re "\$ *$";
interact
I have a bash+expect script which has to connect normal user, i want
to read the specific file and store into the variable to be used
after while that specific file in root user. How can i get the value ?
My script is:
#!/bin/bash
set prompt ">>> "
set command ls /root/test1
expect << EOF
spawn su root
expect "password:"
send "rootroot\r"
expect "$prompt\r"
send "$command\r"
expect "$prompt\r"
expect -re "(.*)\r\n$prompt\r\n"
EOF
echo "$command"
if [ ! -f "$command" ]; then
echo "file is not exist"
else
echo "file is exist"
fi
whenever i'm execute my shell script it show following output:
ls: /root/: Permission denied
file is not exist
basically test is there but it is showing "file is not exist"
This question is very old but i hope someone gets help from this answer.
--> You should use #!/usr/bin/expect or #!/bin/expect to use expect properly, expect<<EOF might work but thats not conventional way to write script.
--> You script should end with EOF statement . Ex.
#!/usr/bin/expect << EOF
<some stuff you want to do>
EOF
--> Some basic thing about spawn. Whatever you write in spawn will execute but it will not have effect on entire script. Its not like environment variables.
In short, spawn will start new process and your command is not under spawn process.
Ex.
#!/usr/bin/expect
spawn bash -c "su root '<your-cmd-as-root>'"
<some-expect-send-stuff-etc>
Now in your script, $command should be write inside spawn like i showed in above example.