Apr 282013

We had a requirement where we had to automate the ssh key transfer as part of a large scale tasks program. The auto ssh was a part of one function of that big app, so after much research we came to know that ‘expect’ is the best tool to do it in easy way.  So before taking leap for the expect command we shall know details about the expect command and its usage.

Expect is a program that “talks” to other interactive programs according to a script. Following the script, Expect knows what can be expected from a program and what the correct response should be. An interpreted language provides branching and high-level control structures to direct the dialogue. In addition, the user can take control and interact directly when desired, afterward returning control to the script. Expectk is a mixture of Expect and Tk. It behaves just like Expect and Tk’s wish. Expect can also be used directly in C or C++ (that is, without Tcl). A very good article about expect can be found here .

You can also check the official site for expect tool : http://expect.nist.gov/

Below are few details about expect from its man pages: man expect
Expect reads cmdfile for a list of commands to execute. Expect may also be invoked implicitly on systems which support the #! nota-
tion by marking the script executable, and making the first line in your script:

#!/usr/local/bin/expect -f

Of course, the path must accurately describe where Expect lives. /usr/local/bin is just an example.

The -c flag prefaces a command to be executed before any in the script. The command should be quoted to prevent being broken up by
the shell. This option may be used multiple times. Multiple commands may be executed with a single -c by separating them with semi-
colons. Commands are executed in the order they appear. (When using Expectk, this option is specified as -command.)

The -d flag enables some diagnostic output, which primarily reports internal activity of commands such as expect and interact. This
flag has the same effect as “exp_internal 1” at the beginning of an Expect script, plus the version of Expect is printed. (The strace
command is useful for tracing statements, and the trace command is useful for tracing variable assignments.) (When using Expectk,
this option is specified as -diag.)

The -D flag enables an interactive debugger. An integer value should follow. The debugger will take control before the next Tcl pro-
cedure if the value is non-zero or if a ^C is pressed (or a breakpoint is hit, or other appropriate debugger command appears in the
script). See the README file or SEE ALSO (below) for more information on the debugger. (When using Expectk, this option is specified
as -Debug.)

The -f flag prefaces a file from which to read commands from. The flag itself is optional as it is only useful when using the #!
notation (see above), so that other arguments may be supplied on the command line. (When using Expectk, this option is specified as

By default, the command file is read into memory and executed in its entirety. It is occasionally desirable to read files one line at
a time. For example, stdin is read this way. In order to force arbitrary files to be handled this way, use the -b flag. (When using
Expectk, this option is specified as -buffer.) Note that stdio-buffering may still take place however this shouldn’t cause problems
when reading from a fifo or stdin.

If the string “-” is supplied as a filename, standard input is read instead. (Use “./-” to read from a file actually named “-“.)

The -i flag causes Expect to interactively prompt for commands instead of reading them from a file. Prompting is terminated via the

exit command or upon EOF. See interpreter (below) for more information. -i is assumed if neither a command file nor -c is used.
(When using Expectk, this option is specified as -interactive.)

— may be used to delimit the end of the options. This is useful if you want to pass an option-like argument to your script without
it being interpreted by Expect. This can usefully be placed in the #! line to prevent any flag-like interpretation by Expect. For
example, the following will leave the original arguments (including the script name) in the variable argv.

#!/usr/local/bin/expect —

Note that the usual getopt(3) and execve(2) conventions must be observed when adding arguments to the #! line.

The file $exp_library/expect.rc is sourced automatically if present, unless the -N flag is used. (When using Expectk, this option is
specified as -NORC.) Immediately after this, the file ~/.expect.rc is sourced automatically, unless the -n flag is used. If the
environment variable DOTDIR is defined, it is treated as a directory and .expect.rc is read from there. (When using Expectk, this
option is specified as -norc.) This sourcing occurs only after executing any -c flags.

-v causes Expect to print its version number and exit. (The corresponding flag in Expectk, which uses long flag names, is -version.)

Optional args are constructed into a list and stored in the variable named argv. argc is initialized to the length of argv.

argv0 is defined to be the name of the script (or binary if no script is used). For example, the following prints out the name of the
script and the first three arguments:

send_user “$argv0 [lrange $argv 0 2]\n”

Much more info can be checked at manual pages of expect by typing man expect in shell prompt.

So after the basic knowledge here comes the shell script to setup autologin to different hosts or for transferring the .pub keys between two hosts.

Below script takes 4 arguments all inline to process the autologin ssh key transfer.

1. Hostname – Hostname of the machine to which you need autologin enabled.

2. Username – The username you want to set for auto login. (can be checked by using ‘whoami’ command in the to hostmachine)

3. Password – Password of the username in remote host.

4. From-username – The username from which you are setting up the auto login ( can be checked by using ‘whoami’ command in the local host)

How to run:

Save the below script as keysetup.exp and give chmod +x keysetup.exp to make it executable

keysetup.exp <hostname> <remote/to-username> <password>  <local/from-username>

./keysetup.exp hkbmachine01.techpaste.com admin4432 myadminpass localadmin


#!/usr/bin/env expect
set host [lrange $argv 0 0]

set username [lrange $argv 1 1]
set password [lrange $argv 2 2]

set lusername [lrange $argv 3 3]
set timeout 10
spawn /usr/bin/ssh-keygen -R $host
spawn /usr/bin/ssh-copy-id -i /home/$lusername/.ssh/id_rsa.pub $username@$host
match_max 100000
expect "*?(yes/no)\?"
send -- "yes\r"
# Look for password prompt
expect {
"*?assword:*" { send -- "$password\r"; send -- "\r"; exp_continue }
eof { exit 1 }
"Now try*\r" { exit 0 }
timeout { exit 1 }
exit 0


Sample Output:

[[email protected] scripts]$ ./keysetup.exp hkbmachine01.techpaste.com appid112 appidpass1 rks
spawn /usr/bin/ssh-keygen -R hkbmachine01.techpaste.com
spawn /usr/bin/ssh-copy-id -i /home/rks/.ssh/id_rsa.pub [email protected]
The authenticity of host 'hkbmachine01.techpaste.com (' can't be established.
RSA key fingerprint is 3c:0b:7f:4b:e8:76:38:f9:da:f1:fa:3f:76:8a:06:7f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'hkbmachine01.techpaste.com,' (RSA) to the list of known hosts.
[email protected]'s password:
Now try logging into the machine, with "ssh [email protected]'", and check in:


to make sure we haven't added extra keys that you weren't expecting.

[[email protected] jarpatch]$ ssh [email protected]
This machine is a legacy host and outside of Devops.



If you get below error while executing, check if you have the keys generated.

spawn /usr/bin/ssh-keygen -R hkbmachine01.techpaste.com
spawn /usr/bin/ssh-copy-id -i /home/rks/.ssh/id_rsa.pub [email protected]
/usr/bin/ssh-copy-id: ERROR: No identities found
send: spawn id exp7 not open
while executing
"send -- "yes\r""
(file "./keysetup.exp" line 12)

To solve this generate the ssh keys in your machine like below:

[[email protected] jarpatch]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/rks/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/rks/.ssh/id_rsa.
Your public key has been saved in /home/rks/.ssh/id_rsa.pub.
The key fingerprint is:
41:84:f4:c6:36:c8:eb:61:86:e6:ca:0e:cb:fc:26:57 [email protected]

Once generated you can now run the key exchange shell script. HTH.

© Incase of any copyright infringements please check copyrights page for faster resolutions.

  One Response to “Shell Script To Automate SSH Key Transfer Between Hosts | Linux”

  1. Amazing blog! Do you have any suggestions for aspiring
    writers? I’m planning to start my own website soon but I’m a
    little lost on everything. Would you recommend starting with a free
    platform like WordPress or go for a paid option? There are so many choices out there that I’m completely confused ..
    Any recommendations? Thanks!

Leave a Reply

Show Buttons
Hide Buttons