Jak pingować w systemie Linux, dopóki host nie będzie znany?

46

Jak mogę pingować określony adres, a gdy go znajdziesz, przestań pingować.

Chcę go używać w skrypcie bash, więc gdy host się uruchamia, skrypt kontynuuje pingowanie i od momentu, gdy host jest dostępny, skrypt kontynuuje ...

Szlifierka Versluys
źródło

Odpowiedzi:

84

Dalsze uproszczenie odpowiedzi Martynas:

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

zauważ, że sam ping jest używany jako test pętli; gdy tylko się powiedzie, pętla kończy się. Ciało pętli jest puste, a komenda „ :” pusta służy do zapobiegania błędowi składni.

Aktualizacja: Pomyślałem o sposobie, aby Control-C opuścił pętlę ping w czysty sposób. Spowoduje to uruchomienie pętli w tle, zatrzymanie sygnału przerwania (Control-C) i zabicie pętli w tle, jeśli się pojawi:

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"

Jest trochę okrężny, ale jeśli chcesz, aby pętla mogła zostać anulowana, powinno wystarczyć.

Gordon Davisson
źródło
6
Aby dodać „sen” (np. Co 5 sekund): póki! ping -c1 www.google.com &> / dev / null; śpij 5; zrobione
lepe
4
Domyślnie pingodczeka 10 sekund, zanim zrezygnuje z pingowania. Jeśli chcesz to skrócić do 1 sekundy, możesz użyć -w1.
Jack O'Connor,
2
@ JackO'Connor Korzystając z BSD ping, jest to stolica-W1
Luke Exton
Moim jedynym problemem z tą odpowiedzią jest to, że nie radzi sobie dobrze z SIGINT. Nie możesz tego zatrzymać z poziomu wiersza poleceń, jeśli nigdy nie będzie się łączył z jakiegokolwiek powodu.
Luke Exton
@LukeExton Wynika to ze sposobu, w jaki bash i ping obsługują SIGINT i ich interakcji (patrz to pytanie ). Nie mam bardzo dobrego rozwiązania, ale jest kluge: użyj Control-Z, aby zatrzymać skrypt, a następnie kill %1go zabić.
Gordon Davisson
25

Możesz zrobić pętlę, wysłać jeden ping i w zależności od stanu przerwać pętlę, na przykład (bash):

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

Umieszczenie tego gdzieś w skrypcie zablokuje, dopóki nie www.google.combędzie możliwe pingowanie.

Martynas Saint
źródło
2
To while truei breakto rozwiązanie czystsze, IMO.
Dan Carley,
1
@ DanCarley Nie zgadzam się z tobą z tego powodu, że w przyjętej odpowiedzi, w wersji z poleceniem zerowym, można zastąpić tryb uśpienia / oczekiwania, aby dać procesorowi przerwę, w którym to przypadku nazwałbym to czystszym rozwiązaniem. Innym problemem związanym z tą odpowiedzią jest to, że wymaga ona od czytelnika / użytkownika zrozumienia, w jaki sposób działa && i jak to się stanie, jeśli pierwsze polecenie zawiedzie, nie zostanie wywołane. To tylko opinia, jak twoja.
Hamid
1
Główną różnicą, którą widzę między tym rozwiązaniem a przyjętym, jest to, że ten echo wyświetli komunikat o błędzie „nieznany host ...”, dopóki nie zostanie znaleziony. Aby dodać sen (np. Co 5 sekund):while true; do sleep 5; ping ...
lepe
20

Wiem, że pytanie jest stare ... i konkretnie dotyczy ping, ale chciałem podzielić się moim rozwiązaniem.

Używam tego podczas ponownego uruchamiania hostów, aby wiedzieć, kiedy mogę ponownie włączyć SSH. (Ponieważ pingbędzie reagować przez kilka sekund przed sshduruchomieniem).

until nc -vzw 2 $host 22; do sleep 2; done
Aaron Copley
źródło
2
Właśnie tego szukałem, dzięki! Możesz nawet przerwać połączenie za pomocą CTRL + C, czego nie ma w przypadku niektórych innych rozwiązań w tym wątku.
Alex
1
Uwaga: działa to dla wersji NetD BSD. Wersja nmap.org w dystrybucjach Linuksa jest zaimplementowana inaczej, więc opcja -z nie istnieje, a opcja -w czeka na połączenie, ale nie zamyka się po pomyślnym zakończeniu. Działa świetnie w OSX.
Paul
Dlatego nie zatrzymujesz się na pierwszej (dobrej) odpowiedzi. To jest odpowiedź na prawdziwy problem.
Leo
11

Wyślij ping do hosta docelowego jeden raz. Sprawdź, czy ping się powiódł (zwracana wartość ping wynosi zero). Jeśli host nie żyje, ping ponownie.

Poniższy kod może zostać zapisany jako plik i wywołany z nazwą hosta jako argumentem lub usunięty z pierwszego i ostatniego wiersza i użyty jako funkcja w istniejącym skrypcie (nazwa hosta waitForHost).

Kod nie ocenia przyczyny niepowodzenia, jeśli ping nie skutkuje odpowiedzią, a zatem zapętla się na zawsze, jeśli host nie istnieje. Moja strona podręczna BSD wymienia znaczenie każdej zwracanej wartości, podczas gdy linux nie, więc myślę, że to może nie być przenośne, dlatego ją pominąłem.

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

Możesz usunąć tryb uśpienia 1, to tylko tutaj, aby zapobiec problemowi z powodzią w przypadku, gdy host byłby dostępny, ale ping nie wychodziłby z kodem 0.

promień
źródło
4

Zobacz dobre opcje w Stackoverflow . Oto przykład w bash, będziesz musiał zapętlić następujący kod, aż zwróci pomyślny wynik ping.


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
źródło
3

dowolna z powyższych pętli może być również używana z fping zamiast pingowania, co IMO lepiej nadaje się do użycia w skryptach niż pingowanie. Szczegóły w fping (1) .

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

przydatne również do testowania, czy maszyny działają, zanim coś na nich zrobią. Prosty przykład:

dla godz. w HOST1 HOST2 HOST3; zrobić
  jeśli fping -q $ h; następnie
     echo -n "$ h:"
     ssh $ h „uname -a”
  fi
gotowy
cas
źródło
1

Spróbuje to podaną liczbę razy.

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

Zamiast echa $rmożesz go przetestować i działać zgodnie z jego wartością:

if ((r)); then echo 'Failed to contact host'; else echo 'Continuing with script'; fi
Dennis Williamson
źródło
1

Aby ładnie obsługiwać SIGINT na BSD ping.

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"

jako funkcja

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
źródło
0

Korzystałem z następującej funkcji. Podoba mi się, ponieważ mogę powiedzieć, żeby przestał próbować po chwili:

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

Można go użyć w ten sposób do uruchomienia czegoś:

# Start-up a web browser, if network is up
if [ $(networkup 60 www.google.com) -eq 0 ]; then
  firefox &
fi
się
źródło
0

Zasadniczo chcę czekać na uruchomienie bazy danych lub innego serwera, ale nie chcę czekać zbyt długo. Poniższy kod czeka przez 10 sekund, a następnie ustawia kod wyjścia, jeśli serwer nie pojawi się w wyznaczonym terminie.

Jeśli serwer pojawi się przed upływem terminu, pętla ulegnie zwarciu, aby można było uruchomić kolejny bit kodu.

for i in `seq 1 10`; do date ; sleep 1 ; ping -c1 ${HOST} &>/dev/null && break ; done
johntellsall
źródło
0

Dalsze udoskonalenie odpowiedzi Gordona Davissona:

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

z otaczającą „$ ()” uruchamiana jest podpowłoka, dlatego można użyć Control-C do zakończenia pętli w przypadku, gdy host nie będzie dostępny.

Shawn  
źródło