¿Cómo hacer ping en Linux hasta que se conozca el host?

46

¿Cómo puedo hacer ping a una determinada dirección y, cuando se encuentra, dejar de hacer ping?

Quiero usarlo en un script bash, por lo que cuando el host se está iniciando, el script continúa haciendo ping y desde el momento en que el host está disponible, el script continúa ...

Sander Versluys
fuente

Respuestas:

84

Una simplificación adicional de la respuesta de Martynas:

until ping -c1 www.google.com >/dev/null 2>&1; do :; done

tenga en cuenta que el ping en sí se usa como prueba de bucle; Tan pronto como tiene éxito, el ciclo termina. El cuerpo del bucle está vacío, con el comando nulo " :" utilizado para evitar un error de sintaxis.

Actualización: pensé en una forma de hacer que Control-C salga limpiamente del bucle de ping. Esto ejecutará el bucle en segundo plano, atrapará la señal de interrupción (Control-C) y matará el bucle de fondo si ocurre:

ping_cancelled=false    # Keep track of whether the loop was cancelled, or succeeded
until ping -c1 "$1" >/dev/null 2>&1; do :; done &    # The "&" backgrounds it
trap "kill $!; ping_cancelled=true" SIGINT
wait $!          # Wait for the loop to exit, one way or another
trap - SIGINT    # Remove the trap, now we're done with it
echo "Done pinging, cancelled=$ping_cancelled"

Es un poco tortuoso, pero si quieres que el bucle sea cancelable, debería ser suficiente.

Gordon Davisson
fuente
66
Para agregar 'dormir' (por ejemplo, cada 5 segundos): mientras! ping -c1 www.google.com &> / dev / null; duerme 5; hecho
lepe
44
Por defecto pingesperará 10 segundos antes de renunciar a su ping. Si desea reducir eso a 1 segundo, puede usarlo -w1.
Jack O'Connor
2
@ JackO'Connor Usando BSD ping, esta es una capital-W1
Luke Exton
Mi único problema con esta respuesta es que no maneja bien SIGINT. No puede detener esto desde la línea de comandos, si nunca se va a conectar por alguna razón.
Luke Exton
@LukeExton Eso se debe a las formas en que bash y ping manejan SIGINT, y cómo interactúan (vea esta pregunta ). No tengo una solución muy buena, pero hay un problema: use Control-Z para detener el script y luego kill %1matarlo.
Gordon Davisson
25

Puede hacer un bucle, enviar un ping y, según el estado, romper el bucle, por ejemplo (bash):

while true; do ping -c1 www.google.com > /dev/null && break; done

Poner esto en algún lugar de su script se bloqueará, hasta que www.google.comsea ​​pingable.

Martynas Saint
fuente
2
Esta while truey breakes la solución más limpia, OMI.
Dan Carley
1
@DanCarley Voy a estar en desacuerdo con usted por la razón de que en la respuesta aceptada, la versión de comando nulo, uno podría sustituir un sueño / espera para darle un descanso a su CPU, y en ese caso lo llamaría la solución más limpia. El otro problema con esta respuesta es que requiere que el lector / usuario entienda cómo funciona el &&, y cómo si el primer comando falla, no se llamará. Esta es solo una opinión, como la tuya.
Hamid
1
La principal diferencia que veo entre esta solución y la aceptada es que esta repetirá el mensaje de error "host desconocido ..." hasta que se encuentre. Para agregar sueño (por ejemplo, cada 5 segundos):while true; do sleep 5; ping ...
lepe
20

Sé que la pregunta es antigua ... y específicamente pregunta sobre ping, pero quería compartir mi solución.

Lo uso cuando reinicio hosts para saber cuándo puedo volver a SSH en ellos. (Dado pingque responderá durante varios segundos antes de sshdcomenzar).

until nc -vzw 2 $host 22; do sleep 2; done
Aaron Copley
fuente
2
Eso es exactamente lo que busqué, ¡gracias! Incluso puede interrumpir la llamada con CTRL + C, que no es el caso para algunas otras soluciones en este hilo.
Alex
1
Tenga en cuenta que esto funciona para las versiones BSD de netcat. La versión nmap.org en las distribuciones de Linux se implementa de manera diferente, por lo que la opción -z no existe y la opción -w espera una conexión pero no se cierra cuando tiene éxito. Sin embargo, funciona muy bien en OSX.
Paul
Es por eso que no te detienes en la primera (buena) respuesta. Esta es la respuesta al problema real .
Leo
11

Haga ping al host de destino una vez. Verifique si el ping tuvo éxito (el valor de retorno de ping es cero). Si el host no está vivo, haga ping nuevamente.

El siguiente código puede guardarse como un archivo y llamarse con el nombre de host como argumento, o despojarse de la primera y última línea y usarse como función dentro de un script existente (waitForHost hostname).

El código no evalúa la causa de la falla si el ping no produce una respuesta, por lo tanto, se repite para siempre si el host no existe. Mi página de manual de BSD enumera el significado de cada valor de retorno, mientras que el de Linux no, así que supongo que esto podría no ser portátil, por eso lo omití.

#!/bin/bash

PING=`which ping`

function waitForHost
{
    if [ -n "$1" ]; 
    then
        waitForHost1 $1;
    else
        echo "waitForHost: Hostname argument expected"
    fi
}

function waitForHost1
{
    reachable=0;
    while [ $reachable -eq 0 ];
    do
    $PING -q -c 1 $1
    if [ "$?" -eq 0 ];
    then
        reachable=1
    fi
    done
    sleep 5
}
waitForHost $1
Jan Jungnickel
fuente
9
UNREACHEABLE=1;
while [ $UNREACHEABLE -ne "0" ]; 
   do ping -q -c 1 HOST &> /dev/null; UNREACHEABLE=$?; sleep 1;
done

Puede eliminar el sueño 1, solo está aquí para evitar cualquier problema de inundación en caso de que el host sea alcanzable pero el ping no salga con el código 0.

radio
fuente
4

Por favor vea buenas opciones en stackoverflow . Aquí hay una muestra en bash, tendrá que recorrer el siguiente código hasta que devuelva un resultado de ping exitoso.


ping -c 1 -t 1 192.168.1.1;
if [ $? -eq 0 ]; then
    echo "192.168.1.1 is up";
else 
    echo "ip is down";
fi

Francois Wolmarans
fuente
3

cualquiera de los bucles anteriores también se puede usar con fping en lugar de ping, lo que, en mi opinión, es más adecuado para usar en scripts que el ping en sí. Ver fping (1) para más detalles.

while ! fping -q $HOSTNAMES ; do :; done

También es útil para probar si las máquinas están funcionando antes de hacer algo en ellas. Un simple ejemplo:

para h en HOST1 HOST2 HOST3; hacer
  si fping -q $ h; entonces
     echo -n "$ h:"
     ssh $ h "uname -a"
  fi
hecho
cas
fuente
1

Esto lo intentará un número dado de veces.

t=4; c=0; r=0; until ping -c 1 hostname.com >/dev/null 2>&1 || ((++c >= t)); do r=$?; done; echo $r

En lugar de hacer eco $r, puede probarlo y actuar de acuerdo con su valor:

if ((r)); then echo 'Failed to contact host'; else echo 'Continuing with script'; fi
Dennis Williamson
fuente
1

Para manejar bien el SIGINT en ping BSD.

HOST=google.com NO=1; while [ $NO -ne 0 ]; do ping -W1 -c1 $HOST &>/dev/null; NO=$?;echo "$(date) ($HOST) $NO" ; done; echo "$(date) ($HOST) reachable"

como una función

ping_until(){
  local NO=1
  while [ $NO -ne 0 ]; do
    ping -W1 -c1 $1 &>/dev/null; NO=$?
    # Optionally block ICMP flooding
    # sleep 1
    echo "$(date) ($1) ($NO)"
  done
}
Luke Exton
fuente
0

He estado usando la siguiente función. Me gusta porque puedo decirle que deje de intentarlo después de un tiempo:

#!/usr/bin/env bash

function networkup {
  # Initialize number of attempts
  reachable=$1
  while [ $reachable -ne 0 ]; do
    # Ping supplied host
    ping -q -c 1 -W 1 "$2" > /dev/null 2>&1
    # Check return code
    if [ $? -eq 0 ]; then
      # Success, we can exit with the right return code
      echo 0
      return
    fi
    # Network down, decrement counter and try again
    let reachable-=1
    # Sleep for one second
    sleep 1
  done
  # Network down, number of attempts exhausted, quiting
  echo 1
}

Se puede usar así para lanzar algo:

# Start-up a web browser, if network is up
if [ $(networkup 60 www.google.com) -eq 0 ]; then
  firefox &
fi
uno mismo
fuente
0

En general, quiero esperar a que aparezca mi base de datos u otro servidor, pero no quiero esperar demasiado . El siguiente código espera durante 10 segundos, luego establece el código de salida si el servidor no apareció dentro del límite de tiempo.

Si el servidor aparece antes del límite de tiempo, el bucle se cortocircuitará para que se pueda ejecutar el siguiente bit de código.

for i in `seq 1 10`; do date ; sleep 1 ; ping -c1 ${HOST} &>/dev/null && break ; done
johntellsall
fuente
0

Una mejora adicional a la respuesta de Gordon Davisson:

until $(ping -c1 www.google.com &>/dev/null); do :; done

con el '$ ()' circundante se inicia una subshell y, por lo tanto, puede usar Control-C para terminar el ciclo en caso de que el host no esté disponible.

Shawn  
fuente