Wie kann man unter Linux pingen, bis der Host bekannt ist?

46

Wie kann ich eine bestimmte Adresse anpingen und beim Auffinden aufhören zu pingen?

Ich möchte es in einem Bash-Skript verwenden. Wenn der Host gestartet wird, pingt das Skript weiter und sobald der Host verfügbar ist, wird das Skript fortgesetzt.

Sander Versluys
quelle

Antworten:

84

Eine weitere Vereinfachung der Antwort von Martynas:

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

Beachten Sie, dass Ping selbst als Schleifentest verwendet wird. Sobald es erfolgreich ist, endet die Schleife. Der Schleifenkörper ist leer, wobei der Befehl " :" null verwendet wird, um einen Syntaxfehler zu verhindern.

Update: Ich habe mir überlegt, wie Control-C die Ping-Schleife sauber verlassen kann. Dadurch wird die Schleife im Hintergrund ausgeführt, das Interrupt-Signal (Control-C) abgefangen und die Hintergrundschleife beendet, falls dies auftritt:

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 ist ein bisschen umständlich, aber wenn Sie möchten, dass die Schleife stornierbar ist, sollte es den Trick tun.

Gordon Davisson
quelle
6
Hinzufügen von "Schlaf" (z. B. alle 5 Sekunden): while! ping -c1 www.google.com &> / dev / null; schlafe 5; done
lepe
4
Standardmäßig pingwird 10 Sekunden gewartet, bevor der Ping aufgegeben wird. Wenn Sie dies auf 1 Sekunde reduzieren möchten, können Sie verwenden -w1.
Jack O'Connor
2
@ JackO'Connor Mit BSD-Ping ist dies eine Hauptstadt-W1
Luke Exton
Mein einziges Problem mit dieser Antwort ist, dass sie SIGINT nicht gut handhabt. Sie können dies nicht über die Befehlszeile stoppen, wenn aus irgendeinem Grund keine Verbindung hergestellt werden soll.
Luke Exton
@LukeExton Das liegt an der Art und Weise, wie Bash und Ping mit SIGINT umgehen und wie sie interagieren (siehe diese Frage ). Ich habe keine sehr gute Lösung, aber es gibt ein Problem: Stoppen Sie das Skript mit Strg-Z und beenden Sie kill %1es dann.
Gordon Davisson
25

Sie können eine Schleife erstellen, einen Ping senden und je nach Status die Schleife unterbrechen, zum Beispiel (bash):

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

Wenn Sie dies irgendwo in Ihr Skript www.google.comeinfügen, wird dies blockiert, bis Ping möglich ist.

Martynas Saint
quelle
2
Dies while trueund breakdie sauberere Lösung, IMO.
Dan Carley
1
@DanCarley Ich werde mit Ihnen nicht einverstanden sein, weil man in der akzeptierten Antwort, der Null-Befehlsversion, einen Schlaf / Warte-Vorgang ersetzen könnte, um Ihrer CPU eine Pause zu geben, und in diesem Fall würde ich es die sauberere Lösung nennen. Das andere Problem bei dieser Antwort ist, dass der Leser / Benutzer verstehen muss, wie das && funktioniert, und dass es nicht aufgerufen wird, wenn der erste Befehl fehlschlägt. Dies ist nur eine Meinung, wie deine eigene.
Hamid
1
Der Hauptunterschied, den ich zwischen dieser und der akzeptierten Lösung sehe, besteht darin, dass diese die Fehlermeldung "unknown host ..." wiederholt, bis sie gefunden wird. So fügen Sie Schlaf (zB alle 5 Sekunden):while true; do sleep 5; ping ...
lepe
20

Ich weiß, die Frage ist alt ... und fragt speziell nach ping, aber ich wollte meine Lösung teilen.

Ich benutze dies, wenn ich Hosts neu starte, um zu wissen, wann ich wieder in sie SSH kann. (Da pingwird für einige Sekunden reagiert, bevor sshdgestartet wird.)

until nc -vzw 2 $host 22; do sleep 2; done
Aaron Copley
quelle
2
Genau das habe ich gesucht, danke! Sie können den Anruf sogar mit STRG + C unterbrechen, was bei einigen anderen Lösungen in diesem Thread nicht der Fall ist.
Alex
1
Beachten Sie, dass dies für BSD-Versionen von Netcat funktioniert. Die nmap.org-Version in Linux-Distributionen ist anders implementiert, sodass die Option -z nicht vorhanden ist und die Option -w auf eine Verbindung wartet, aber bei Erfolg nicht geschlossen wird. Funktioniert jedoch hervorragend unter OSX.
Paul
Deshalb hören Sie nicht bei der ersten (feinen) Antwort auf. Dies ist die Antwort auf das eigentliche Problem.
Leo vor
11

Pingen Sie den Zielhost einmal. Überprüfen Sie, ob der Ping erfolgreich war (Rückgabewert von Ping ist Null). Wenn der Host nicht am Leben ist, pingen Sie erneut.

Der folgende Code kann als Datei gespeichert und mit dem Hostnamen als Argument aufgerufen oder von der ersten und letzten Zeile befreit und als Funktion in einem vorhandenen Skript (waitForHost-Hostname) verwendet werden.

Der Code wertet die Fehlerursache nicht aus, wenn der Ping nicht zu einer Antwort führt. Wenn der Host nicht vorhanden ist, wird eine Endlosschleife ausgeführt. Meine BSD-Manpage listet die Bedeutung der einzelnen Rückgabewerte auf, während die Linux-Manpage dies nicht tut. Deshalb habe ich sie weggelassen.

#!/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
quelle
9
UNREACHEABLE=1;
while [ $UNREACHEABLE -ne "0" ]; 
   do ping -q -c 1 HOST &> /dev/null; UNREACHEABLE=$?; sleep 1;
done

Sie können den Ruhezustand 1 entfernen. Er dient nur dazu, Überschwemmungsprobleme zu vermeiden, wenn der Host erreichbar ist, Ping jedoch nicht mit Code 0 beendet wird.

Radius
quelle
4

Bitte sehen Sie gute Optionen bei Stackoverflow . Hier ist ein Beispiel in Bash. Sie müssen den folgenden Code durchlaufen, bis ein erfolgreiches Ping-Ergebnis zurückgegeben wird.


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
quelle
3

Jede der obigen Schleifen kann auch mit fping anstelle von ping verwendet werden. IMO ist für die Verwendung in Skripten besser geeignet als Ping. Siehe fping (1) für Details.

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

Auch nützlich, um zu testen, ob die Maschinen in Betrieb sind, bevor Sie etwas an ihnen tun. Ein einfaches Beispiel:

für h in HOST1 HOST2 HOST3; machen
  if fping -q $ h; dann
     echo -n "$ h:"
     ssh $ h "uname -a"
  fi
getan
cas
quelle
1

Dies wird eine bestimmte Anzahl von Malen versuchen.

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

Anstatt zu wiederholen $r, können Sie es testen und entsprechend seinem Wert handeln:

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

Um mit dem SIGINT auf BSD-Ping gut umzugehen.

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"

als eine Funktion

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
quelle
0

Ich habe die folgende Funktion verwendet. Ich mag es, weil ich sagen kann, dass es nach einer Weile aufhören soll, es zu versuchen:

#!/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
}

Es kann so benutzt werden, um etwas zu starten:

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

Im Allgemeinen möchte ich warten, bis meine Datenbank oder ein anderer Server hochgefahren ist, aber ich möchte nicht zu lange warten . Der folgende Code wartet 10 Sekunden und legt dann den Beendigungscode fest, wenn der Server nicht innerhalb des Zeitlimits angezeigt wurde.

Wenn der Server vor dem Zeitlimit angezeigt wird, wird die Schleife kurzgeschlossen, damit das nächste Codebit ausgeführt werden kann.

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

Eine weitere Verbesserung der Antwort von Gordon Davisson:

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

mit dem umgebenden '$ ()' wird eine Subshell gestartet und Sie können daher Control-C verwenden, um die Schleife zu beenden, falls der Host nicht verfügbar wird.

Shawn  
quelle