[Script] Mejorando la productividad: Automatizando conexiones SSH mediante expect

Trabajo mucho con máquinas remotas, en estos casos me gusta abrir mi terminal y conectarme rapidamente utilizando SSH, lo cual no siempre es «tan rápido» porque he de introducir la contraseña u otros parametros de inicio. Para estos casos recomiendo utilizar aplicaciones tan geniales como Pac Manager, que nos simplifica mucho estas tareas o habilitar la posibilidad de conexion SSH sin necesidad de usar contraseña (mediante clave pública). Pero no siempre podemos hacer lo que queramos en máquinas ajenas o instalar software adicional, asi que me plantee crearme unos sencillos scripts que me permitan acceder rapidamente a todas las máquinas remotas que necesite mediante SSH. Son los siguientes y puedes mejorarlos o personalizarlos como necesites.

conectar

conectar es el script principal, es un script que utiliza el comando «expect» (deberás tenerlo instalado en la máquina) y recupera los siguientes parametros que se le pasan por la linea de comandos: máquina, usuario, password, directorio de inicio y caracter usado para el prompt. Su funcionalidad es tan simple como automatizar la conexion ssh de manera que no sea necesario indicar la password y que nos deje en el directorio indicado. Entonces inicia una sesión interactiva para que escribamos los comandos que necesitemos en la máquina remota.

#!/usr/bin/expect

set host [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set prompt [lindex $argv 3]
set directorio [lindex $argv 4]

spawn  ssh $user@$host
expect "password:"
send "$password\n";
expect "$prompt"
send "cd $directorio\n";
expect "$prompt"
interact

c.txt

Es el fichero que utilizo como base de datos para guardar los datos de las máquinas remotas. Pienso utilizar sqlite más adelante pero no queria complicarlo mucho inicialmente para aquellos que desconozcan el uso de sqlite. El fichero es de la forma:

soledad|127.0.0.1|jose|jose|/home/jose/Escritorio|>|SSH|Mi servidor ssh
# Formato: alias | ip | user | password | directorio | prompt | protocolo | descripcion

Es decir, añades una linea por cada máquina a la que quieras conectar y en esta linea indicas el nombre de la conexion (alias a usar), la dirección ip de la máquina, el usuario con el que conectar, la password, el directorio base de inicio donde quieres quedarte al inicio de la sesión, el prompt utilizado y el protocolo.

c

Es el script de bash que se encarga de llamar al script de expect (conectar) con los parametros adecuados. Su función principal es a partir de un alias que se le pasa como parametro, examinar el fichero c.txt y extraer la ip, user, password y directorio de esa máquina, para pasarle esos parametros a expect (script conectar). Si no se le pasa ningún parametro lo que hace es imprimir la lista actual de alias del fichero c.txt a modo de recuerdo de las máquinas a las que puedes conectar.


#!/bin/bash

CONSOLA=false
repo="${HOME}/UTIL/c.txt"
RUTA_LIB="${HOME}/UTIL/"

function DEBUG()
{
	if ( $CONSOLA )
	then
		echo "DEBUG: $1 \n"
	fi
}
#-----

GET_IP()
{
	busqueda="$1"
	#DEBUG "Buscando por : [ $busqueda ]"
	cat $repo | grep $busqueda | awk -F"|" '{print $2}'

}
#----

GET_USER()
{
	busqueda="$1"
	#DEBUG "Buscando por : [ $busqueda ]"
	cat $repo | grep $busqueda | awk -F"|" '{print $3}'

}
#----

GET_PASSWORD()
{
	busqueda="$1"
	#DEBUG "Buscando por : [ $busqueda ]"
	cat $repo | grep $busqueda | awk -F"|" '{print $4}'

}
#----

GET_DIRECTORIO()
{
	busqueda="$1"
	#DEBUG "Buscando por : [ $busqueda ]"
	cat $repo | grep $busqueda | awk -F"|" '{print $5}'

}
#----

CONECTAR_SSH()
{
	${RUTA_LIB}conectar "$1" "$2" "$3" "$4" "$5"
}

SSH()
{
alias="$1"
_Host=`GET_IP "$alias"`
_User=`GET_USER "$alias"`
_Pass=`GET_PASSWORD "$alias"`
_Directorio=`GET_DIRECTORIO "$alias"`
_Prompt=">"
CONECTAR_SSH "$_Host" "$_User" "$_Pass" "$_Prompt" "$_Directorio"
}

ALIASNAME="$1"
if [ -z $ALIASNAME ];
then
	echo "Sintaxis: $0 <alias o nombre maquina>"
	echo ""
	echo "Conexiones disponibles:"
	echo "-----------------------"
	echo ""
	tac $HOME/UTIL/c.txt | grep -v "#" | awk -F"|" '{print $1}' | sort

else
	SSH "$1"
fi;

Nota importante: por defecto todos estos scripts deben estar ubicados en $HOME/UTIL aunque se podria editar fácilmente el último script para que utilizara otro path.

Nota 2: el prompt de momento no lo uso y paso por defecto «>» pero es fácil de usar el que sea necesario. p.ej «$»

Por último sólo seria necesario crear el siguiente «alias» en nuestro fichero .bashrc

alias sshe=’$HOME/UTIL/c \$1′

Uso «sshe» por que me recuerda a «ssh y la e es de expect» pero podrias usar cualquier otro nombre.

Ahora conectar a cualquier máquina es tán simple como ejecutar desde consola:

$ sshe alias_de_la_maquina

Ejemplo:

$ sshe soledad

(usa tus propias máquinas de acuerdo al fichero c.txt)

y los scripts anteriores ya se encargan de dejarte el terminal preparado con la conexión ssh abierta.

He preparado un instalador que se encarga de copiar ya todo a tu directorio $HOME/UTIL. Puedes descargarlo junto al resto de scripts del siguiente enlace (nota: wordpress no me deja subir ficheros .zip directamente , asi que está renombrado como .doc pero realmente es un fichero .zip, cambiale la extensión y ya lo podrás descomprimir).

Espero que sea útil, a mi por lo menos si que me lo resulta.

Descarga | SSHE.zip

29 Respuestas to “[Script] Mejorando la productividad: Automatizando conexiones SSH mediante expect”


  1. 1 Cristoph febrero 17, 2011 a las 4:44 am

    Wena, bonito script, ingenioso!!!

    Hablando de PAC MANAGER os sugiero probar GCM lo pueden bajar de http://kuthulu.com/gcm/

    Muy buen blog, sigue asi

    Saludos

  2. 2 Reoba febrero 17, 2011 a las 7:34 am

    Gracias amigo, le hechare un vistazo 😉

    Saludos

  3. 3 Angel febrero 17, 2011 a las 7:37 am

    Hola,

    Lo primero, gracias por el script.

    Estaba cambiando las rutas y en el listado de conexiones tienes
    tac $HOME/UTIL/c.txt
    con la ruta fija en vez de utilizar $repo definido antes.

    Para poder utilizar el autocompletado de bash he escrito el siguiente archivo

    /etc/bash_completion.d/sshe
    ———————————-
    _sshe()
    {

    COMPREPLY=()
    cur=`_get_cword`
    prev=${COMP_WORDS[COMP_CWORD-1]}

    COMPREPLY=( $( compgen -W ‘$( command cat $HOME/UTIL/c.txt |cut -d»|» -f 1)’ «$cur») )

    }
    complete -F _sshe sshe
    ——————————————

    Así con el tabulador te autocompleta el comando sshe

  4. 5 Joss febrero 17, 2011 a las 8:23 am

    Hola, están muy bien los scripts, pero realmente, cuales son las ventajas? qué te permiten hacer que no puedas si te autentificas con ssh por «clave pública» ?

    Un saludo!

    • 6 t.a.c. febrero 17, 2011 a las 9:12 am

      Eso mismo iba a decir yo. Este método implica que hay un sitio donde está escrita la clave explícitamente, si lo entiendo bien. No veo que sea más seguro que usar una clave pública.

      Además con clave pública puedes automatizar rsync, por ejemplo, sin mucha complicación.

      • 7 jose febrero 17, 2011 a las 11:09 am

        Claro que es mejor. pero no siempre las maquinas son tuyas, el administrador te deja conectar de esa manera, o son demasiadas maquinas o sujetas a cambios de ip, dns.
        Este metodo es para esas veces que te conectas y no te queda otra que indicar el user y la password.

      • 8 HaSsEs febrero 17, 2011 a las 3:51 pm

        Además de lo que dice «jose», con software como PAC Manaer puedes conectar varios terminales en modo *cluster*: lo que hagas/teclees en uno, se replica en todos los terminales de dicho cluster! Dejo a tu imaginación las aplicaciones que eso puede tener! 😉

    • 9 Joss febrero 18, 2011 a las 7:54 pm

      Bueno, si, en esos casos que comentas puede ser muy cómodo el script, ya que no se le puede pasar un password como parámetro al comando ssh.

      Un saludo!

  5. 10 juanxyu febrero 17, 2011 a las 5:41 pm

    Hola,

    Debes hacer una leve modificación al formato de las conexiones: Después del password se debe especificar el prompt y luego el directorio porque en «conectar» se espera de esa forma

    set host [lindex $argv 0]
    set user [lindex $argv 1]
    set password [lindex $argv 2]
    set prompt [lindex $argv 3]
    set directorio [lindex $argv 4]

    Gracias por el script, me es muy útil 😀

    • 11 juanxyu febrero 17, 2011 a las 6:00 pm

      Hola otra vez,

      Debo corregir mi corrección 😛

      No se por qué pero con al conectarme a las máquinas el comando cd SHOME/usuario se queda encolado o algo así y lo ejecuta sola hasta que ingresó otro comando. Tocando aquí y allá los scripts lo «solucioné» dejando el formato de las conexiones en el orden inicial solo que el campo de directorio lo de jo vacío y en «conectar» dejé los set de la siguiente forma:

      set host [lindex $argv 0]
      set user [lindex $argv 1]
      set password [lindex $argv 2]
      set prompt [lindex $argv 4]
      set directorio [lindex $argv 3]

      Con estos cambio me funciona perfecto.

      Gracias nuevamente!!!

  6. 12 Alex U marzo 2, 2011 a las 10:20 pm

    Buenas tardes. El script es muy interesante, pero quería molestarte preguntando algo.

    Estoy haciendo ping a los router conectados a un server linux con debian desde otro equipo cliente.

    Las IP las tengo cargadas en un archivo ip.txt; necesito hacer ping desde el servidor a todas las IP y guardar el resultado en un LOG; sin embargo no he podido lograrlo puesto que si leo los datos desde un archivo, al generar un bucle para leerlo (con while) en ese bucle entra la conexión SSH.

    El código que uso es:

    #!/bin/bash
    # Bash commands go here
    host=»10.10.10.10″
    user=»user»
    password=»101010″
    salir=»logout»
    while read ping1
    do
    #***************************EXPECT****************************

    /usr/bin/expect << EndMark

    #************inicio del contacto ssh***************

    spawn ssh $user@$host
    expect "password:" { send "$password\r"}
    log_file ip.txt

    #*************************************************************
    #************inicio del contacto ssh con pig a routers*********
    #**********************************************************
    expect "$ " {send "ping -c 1 -w 1 -s 1 $ping1\r\r"}
    #*************************************************************
    #************salgo de ssh************************
    #**********************************************************
    expect "$ " {send "$salir\r"}

    EndMark

    done < ip.txt

    Como pueden ver, la conexión ssh queda dentro del while que lee cerca de 200 líneas, por lo que realiza la petición ssh 200 veces y genera muchos incovenientes.

    Mi ideal es realizar una sola conexión, que lea las ip, realice el ping y guarde el log para leerlo y saber que pinga esta caìda y cuál no.

    Agradezco toda la colaboración posible y más que nada su atención

    • 13 jose marzo 2, 2011 a las 11:00 pm

      no se, es raro. y si pruebas a no meter la conexion ssh directamente en el propio script sino utilizar un script auxiliar en plan:

      conectar.sh «ip» «user» «pass»

      y en tu script principal, dentro del bucle llamas al anterior

      while bucle do
      ./conectar.sh ristra_de_parametros
      done

      siempre puedes capturar el output si redireccionas o utilizas tee

      conectar.sh «parametros» | tee fichero.salida

  7. 14 Alex U marzo 3, 2011 a las 1:32 pm

    Gracias por la respuesta.
    Perdona, pero no me queda muy claro, sería algo como:
    crear un script de conexión, algo como:
    sonectarssh.sh:
    /usr/bin/expect
    spawn ssh $user@$host
    expect «password:» { send «$password\r»}

    Y este script lo invoco antes del while, algo así:

    #!/bin/bash
    host=”10.10.10.10″
    user=”user”
    password=”101010″
    salir=”logout”
    ./conectarssh.sh
    while read ping1
    do
    #***************************EXPECT****************************

    /usr/bin/expect << EndMark
    expect "$ " {send "ping -c 1 -w 1 -s 1 $ping1\r\r"}
    EndMark
    done < ip.txt

    Muchas gracias por la ayuda.

  8. 15 Alex U marzo 3, 2011 a las 3:57 pm

    Te comento, cree 2 scripts, el primero contiene únicamente la conexión ssh con expect(no tengo permisos en el servidor para establecer llaves, por lo que debo automatizar el ingreso), el segundo tiene el bucle while junto con las demàs instrucciones expect.

    Cuando llamo al script de conexión fuera del bucle:
    ./conex.sh
    while bucle do
    comandos expec
    Me cierra la conexión antes de entrar al bucle; si lo llamo dentro del bucle
    #!/usr/bin
    variables….
    while bucle do
    ./conex.sh
    comandos expec

    Pasa lo de siempre, cada que lee una línea, me conecta por ssh, es decir, me conecta por ssh cada vez que hago un ping.

    Estoy algo perdido aún.

    • 16 Lobo marzo 21, 2011 a las 7:59 pm

      Mmm, claro en este caso solo te puede servir para ejecutar un comando remoto en alguna maquina y salir, sin manterner la sesión.

      si haces un

      ./conex.sh «ip1» «password1» etc…
      ./conex.sh «ip2» «passoword2» etc

      te va bien?

      entonces tienes que buscar la forma de pasar esas variables en cada iteracion del bucle.

      A ver si puedo publicar un ejemplillo pronto, pero vamos, he hecho eso en otras ocasiones y no me ha dado mucho problema.

  9. 17 Luis junio 7, 2011 a las 9:09 am

    Hola, gracias por el script en primer lugar.

    Te comento: estuve modificando un poco tu script para conectarme desde una maquina A por ssh a una máquina B para que a continuación B envíe un mail usando telnet y smtp.

    Básicamente sólo añado el argumento $envia en tu fichero c
    —————————–

    envia='(sleep 2 ; echo «helo algo.com» ; sleep 2 ; echo «mail from: algo@algo.com» ; sleep 2 ; echo «rcpt to: algo@algo.com» ; sleep 2 ; echo «data» ; sleep 2 ; echo «To: algo@algo.com» ; sleep 2 ; echo «From: algo@algo.com» ; sleep 2 ; echo «Subject: Test Restore OK `date`» ; sleep 2 ; echo «» ; sleep 2 ; echo «Conetnido del mensaje» ; sleep 2 ; echo «» ; sleep 2 ; echo «.» ; sleep 2 ; echo «» ;)|telnet ip.dir.smtp puerto’

    CONECTAR_SSH()
    {
    ${RUTA_LIB}conectar «$1» «$2» «$3» «$4» «$5» «$envia»
    }

    ———————

    Todo funciona correctamente si lanzo el script a mano pero si lo programo con cron no funciona.
    Al redireccionar la salida a un fichero salen símbolos raros al lanzar el script con cron, lo que no hace si se lanza a mano.

    (sleep 2 ; echo «helo algo.com» ; sleep 2 ; echo «ma
    <ep 2 ; echo "helo algo.com" ; sleep 2 ; echo "mai l from:

    Si se te ocurre de que puede ser te lo agradecería.

    Un saludo y muchas gracias

  10. 18 Oscar octubre 17, 2011 a las 10:39 am

    éste script para un sysadmin viene como anillo al dedo, gracias, solo me gustaria hacer una sugerencia, mas que en la programación del script es en el instalador, es viable que desde el instalar tu indique en que directorio quieras instalarlo y automaticamente se cambien tambien todos los path de los script?

    saludos y buen trabajo, excelente

  11. 19 Oscar octubre 17, 2011 a las 11:06 am

    otra cosa que me percato es que el script no permite usar como contraseñas caracteres especiales :s hay alguna manera de solucionar esto, un saludo y gracias nuevamente 🙂

  12. 20 Eder marzo 13, 2012 a las 1:25 am

    Mis felicitaciones. ES muy ocurrente la verdad. Sólo por sacar una pega ;D diría que le falta un campo para el puerto en el .txt pero bueno eso en unos minutos se puede personalizar.

    MUY BUENO!

  13. 21 Guillermo May 14, 2012 a las 7:03 pm

    Viejo! Sos un genio. Te agradezco un monton!

  14. 22 Gonzao junio 11, 2012 a las 1:03 pm

    Alex U: puedes ejecutar ping -c 1, este comando enviará sólo un request ICMP.

  15. 23 MorenoYo octubre 10, 2019 a las 1:14 am

    Buenas amig@s… requiero una ayuda…
    Estoy tratando de conectarme con varios servidores mediante ssh para ejecutar varios comandos que me deben traer información acerca de los mismos… hice la prueba de conexión con un solo servidor, se conecta pero se desconecta rapidamente…para cada servidor se deben ejecutar 5 comandos y las salidas deben quedar en un archivo .txt en determinada ruta… No se cómo hacerlo. Les agradezco inmensamente su valiosa colaboración…


  1. 1 gnome-connection-manager: “Genial” administrador para tus conexiones SSH « Ubuntu Life Trackback en febrero 17, 2011 a las 11:44 am
  2. 2 Lo mejor de mi RSS del 14 al 20 de febrero | Linux Hispano Trackback en febrero 20, 2011 a las 3:52 am
  3. 3 Script en Bash para ejecutar un comando remoto mediante SSH | Blog de Informática Peula Trackback en junio 27, 2013 a las 9:23 am
  4. 4 sshpass: Enviar el password desde la linea de comandos en conexiones ssh | Ubuntu Life Trackback en marzo 15, 2016 a las 7:49 pm
  5. 5 donacion de ovulos precio en venezuela Trackback en marzo 20, 2016 a las 8:24 am
  6. 6 Conectar a equipo remoto con cliente SSH | ZeppelinuX Trackback en abril 27, 2017 a las 7:01 pm

Replica a juanxyu Cancelar la respuesta







¿Es compatible tu equipo con Ubuntu?


( Muchos fondos de pantalla, aqui )

DESCARGATE SCIFI LIFE

365 Dias de Soledad
Me debes los sueños, las promesas y las noches rotas. Me debes la paz, la sonrisa y la esperanza robadas. Me debes la sangre, las lágrimas y el sudor vertido. Me debes las noches vacías, los abrazos anhelados. Me debes un beso de ajenjo de tu amarga boca.

The Ubuntu Counter Project - user number # 11961
Geo Visitors Map

Archivos

febrero 2011
L M X J V S D
 123456
78910111213
14151617181920
21222324252627
28  

Blog Stats

  • 31.398.051 hits