Come eseguire il ping in Linux fino a quando l'host è noto?


46

Come posso eseguire il ping di un determinato indirizzo e, una volta trovato, interrompere il ping.

Voglio usarlo in uno script bash, quindi quando l'host si avvia, lo script continua a eseguire il ping e dal momento in cui l'host è disponibile, lo script continua ...

Risposte:


84

Un'ulteriore semplificazione della risposta di Martynas:

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

si noti che il ping stesso viene utilizzato come test di loop; non appena riesce, il ciclo termina. Il corpo del ciclo è vuoto, con il comando null " :" utilizzato per prevenire un errore di sintassi.

Aggiornamento: ho pensato a un modo per far sì che Control-C uscisse dal loop ping in modo pulito. Questo eseguirà il loop in background, intercetterà il segnale di interruzione (Control-C) e ucciderà il loop in background se si verifica:

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"

È un po 'tortuoso, ma se vuoi che il loop sia cancellabile dovrebbe fare il trucco.


6
Per aggiungere "sleep" (ad es. Ogni 5 secondi): while! ping -c1 www.google.com &> / dev / null; dormire 5; fatto
lepe

4
Di default pingattenderà 10 secondi prima di rinunciare al suo ping. Se vuoi ridurlo a 1 secondo, puoi usare -w1.
Jack O'Connor,

2
@ JackO'Connor Usando il ping BSD, questa è una capitale-W1
Luke Exton

Il mio unico problema con questa risposta è che non gestisce bene SIGINT. Non è possibile interrompere ciò dalla riga di comando, se non si connetterà mai per qualsiasi motivo.
Luke Exton,

@LukeExton Questo è dovuto al modo in cui bash e ping gestiscono SIGINT e al modo in cui interagiscono (vedi questa domanda ). Non ho un'ottima soluzione, ma c'è un kluge: usa Control-Z per fermare lo script, quindi kill %1per ucciderlo.
Gordon Davisson,

25

Puoi fare un loop, inviare un ping e, a seconda dello stato, interrompere il loop, ad esempio (bash):

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

Metterlo da qualche parte nel tuo script verrà bloccato, fino a quando non www.google.comè possibile eseguire il ping.


2
Questa while trueed breakè la soluzione più pulita, IMO.
Dan Carley,

1
@DanCarley Non sono d'accordo con te per il motivo che nella risposta accettata, nella versione con comando null, si potrebbe sostituire una sospensione / attesa per dare una pausa alla CPU, e nel qual caso la definirei la soluzione più pulita. L'altro problema con questa risposta è che richiede al lettore / utente di capire come funziona && e come se il primo comando fallisce, non verrà chiamato. Questa è solo un'opinione, come la tua.
Hamid,

1
La differenza principale che vedo tra questa soluzione e quella accettata è che questa farà eco al messaggio di errore "host sconosciuto ..." fino a quando non viene trovata. Per aggiungere il sonno (ad esempio ogni 5 secondi):while true; do sleep 5; ping ...
lepe

20

So che la domanda è vecchia ... e in particolare chiede riguardo ping, ma volevo condividere la mia soluzione.

Lo uso quando riavvio gli host per sapere quando posso SSH di nuovo in loro. (Dal momento pingche risponderà per diversi secondi prima che sshdvenga avviato.)

until nc -vzw 2 $host 22; do sleep 2; done

2
È esattamente quello che ho cercato, grazie! Puoi persino interrompere la chiamata con CTRL + C, il che non è il caso di altre soluzioni in questo thread.
Alex,

1
Nota che funziona per le versioni BSD di netcat. La versione nmap.org nelle distribuzioni Linux è implementata in modo diverso, quindi l'opzione -z non esiste e l'opzione -w attende una connessione ma non si chiude in caso di successo. Funziona benissimo in OSX, però.
Paul,

Questo è il motivo per cui non ti fermi alla prima (buona) risposta. Questa è la risposta al vero problema.
Leo,

11

Effettua il ping dell'host di destinazione una volta. Controlla se il ping è riuscito (il valore di ritorno del ping è zero). Se l'host non è attivo, eseguire nuovamente il ping.

Il seguente codice può essere salvato come file e chiamato con il nome host come argomento oppure rimosso dalla prima e dall'ultima riga e utilizzato come funzione all'interno di uno script esistente (waitForHost hostname).

Il codice non valuta la causa dell'errore se il ping non provoca una risposta, quindi esegue un ciclo continuo se l'host non esiste. La mia manpage BSD elenca il significato di ogni valore di ritorno, mentre quello di Linux no, quindi immagino che questo potrebbe non essere portatile, ecco perché l'ho lasciato fuori.

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

9
UNREACHEABLE=1;
while [ $UNREACHEABLE -ne "0" ]; 
   do ping -q -c 1 HOST &> /dev/null; UNREACHEABLE=$?; sleep 1;
done

Puoi rimuovere sleep 1, è qui solo per prevenire qualsiasi problema di allagamento nel caso in cui l'host fosse raggiungibile ma il ping non uscisse con il codice 0.


4

Si prega di vedere buone opzioni su StackOverflow . Ecco un esempio in bash, dovrai scorrere il seguente codice fino a quando non restituisce un risultato ping riuscito.


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


3

uno qualsiasi dei loop di cui sopra può anche essere usato con fping piuttosto che con ping che, IMO, è più adatto per l'uso negli script rispetto al ping stesso. Vedi fping (1) per i dettagli.

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

utile anche per verificare se le macchine sono attive prima di fare qualcosa su di esse. Un semplice esempio:

per h in HOST1 HOST2 HOST3; fare
  se fping -q $ h; poi
     echo -n "$ h:"
     ssh $ h "uname -a"
  fi
fatto

1

Questo proverà un determinato numero di volte.

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

Invece di fare eco $r, puoi testarlo e agire in base al suo valore:

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

1

Per gestire bene il SIGINT sul 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"

come una funzione

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
}

0

Sto usando la seguente funzione. Mi piace perché posso dire che smette di provare dopo un po ':

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

Può essere usato in questo modo per lanciare qualcosa:

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

0

In generale, voglio attendere che il mio database o un altro server venga visualizzato, ma non voglio aspettare troppo a lungo. Il codice seguente attende 10 secondi, quindi imposta il codice di uscita se il server non è stato visualizzato entro il limite di tempo.

Se il server viene visualizzato prima del limite di tempo, il ciclo verrà cortocircuitato in modo che il prossimo bit di codice possa essere eseguito.

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

0

Un ulteriore miglioramento della risposta di Gordon Davisson:

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

con il '$ ()' circostante viene avviata una subshell e quindi è possibile usare Control-C per terminare il ciclo nel caso in cui l'host non diventi disponibile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.