Comment faire un ping sous Linux jusqu'à ce que l'hôte soit connu?

46

Comment puis-je cingler une certaine adresse et quand trouvé, arrêtez de cingler.

Je veux l'utiliser dans un script bash. Ainsi, lorsque l'hôte démarre, le script continue à envoyer des requêtes ping et à partir du moment où l'hôte est disponible, le script continue ...

Sander Versluys
la source

Réponses:

84

Une simplification supplémentaire de la réponse de Martynas:

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

notez que le ping lui-même est utilisé comme test de boucle; dès qu'elle réussit, la boucle se termine. Le corps de la boucle est vide, avec la commande null " :" utilisée pour empêcher une erreur de syntaxe.

Mise à jour: j'ai pensé à un moyen de forcer Control-C à quitter la boucle de ping proprement. Cela exécutera la boucle en arrière-plan, interceptera le signal d'interruption (Control-C) et supprimera la boucle d'arrière-plan s'il se produit:

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"

C'est un peu détourné, mais si vous voulez que la boucle soit annulable, elle devrait faire l'affaire.

Gordon Davisson
la source
6
Pour ajouter 'sommeil' (par exemple chaque 5 secondes): while! ping-c1 www.google.com &> / dev / null; dors 5; terminé
lepe
4
Par défaut ping, attendra 10 secondes avant d'abandonner son ping. Si vous voulez réduire cela à 1 seconde, vous pouvez utiliser -w1.
Jack O'Connor
2
@ JackO'Connor En utilisant le ping BSD, c'est une capitale-W1
Luke Exton
Mon seul problème avec cette réponse est qu'il ne gère pas bien SIGINT. Vous ne pouvez pas arrêter cela à partir de la ligne de commande, si elle ne se connecte jamais pour une raison quelconque.
Luke Exton
@LukeExton Cela est dû à la manière dont bash et ping gèrent SIGINT et à la manière dont ils interagissent (voir cette question ). Je n'ai pas une très bonne solution, mais il y a un problème: utilisez Control-Z pour arrêter le script, puis kill %1pour le tuer.
Gordon Davisson
25

Vous pouvez faire une boucle, envoyer un ping et en fonction de l’état, casser la boucle, par exemple (bash):

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

Mettre ceci quelque part dans votre script bloquera, jusqu'à ce que www.google.comsoit pingable.

Martynas Saint
la source
2
Ceci while trueet breakest la solution plus propre, IMO.
Dan Carley
1
@DanCarley Je ne suis pas d'accord avec vous pour la raison que dans la réponse acceptée, la version de commande nulle, on pourrait substituer une veille / attente pour donner une pause à votre processeur, et dans ce cas, je l'appellerais la solution plus propre. L’autre problème de cette réponse est que le lecteur / utilisateur doit comprendre comment fonctionne le && et comment, si la première commande échoue, elle ne sera pas appelée. Ceci est juste un avis, comme le vôtre.
Hamid
1
La principale différence que je vois entre cette solution et celle acceptée est que celle-ci fera écho au message d'erreur "hôte inconnu ..." jusqu'à ce qu'il soit détecté. Pour ajouter du sommeil (par exemple chaque 5 secondes):while true; do sleep 5; ping ...
lepe
20

Je sais que la question est ancienne ... et demande spécifiquement en ce qui concerne ping, mais je voulais partager ma solution.

J'utilise cette information lors du redémarrage des hôtes pour savoir quand je pourrai SSH y revenir. (Depuis pingrépondra pendant plusieurs secondes avant de sshdcommencer.)

until nc -vzw 2 $host 22; do sleep 2; done
Aaron Copley
la source
2
C'est exactement ce que j'ai cherché, merci! Vous pouvez même interrompre l'appel avec CTRL + C, ce qui n'est pas le cas pour d'autres solutions de ce fil.
Alex
1
Notez que cela fonctionne pour les versions BSD de netcat. La version de nmap.org dans les distributions Linux étant implémentée différemment, l'option -z n'existe pas et l'option -w attend une connexion, mais ne ferme pas en cas de succès. Fonctionne très bien sous OSX.
Paul le
C'est pourquoi vous ne vous arrêtez pas à la première réponse. C'est la réponse au vrai problème.
Leo
11

Cinglez l'hôte cible une fois. Vérifiez si le ping a réussi (la valeur renvoyée par ping est zéro). Si l'hôte n'est pas en vie, cinglez à nouveau.

Le code suivant peut être enregistré en tant que fichier et appelé avec le nom d'hôte en tant qu'argument, ou supprimé de la première et de la dernière ligne et utilisé en tant que fonction dans un script existant (nom d'hôte waitForHost).

Le code n'évalue pas la cause de l'échec si le ping ne donne pas de réponse, bouclant ainsi à tout jamais si l'hôte n'existe pas. Ma page de manuel BSD répertorie la signification de chaque valeur de retour, contrairement à celle de Linux. Je suppose donc que cela n’est peut-être pas portable, c’est pourquoi je l’ai omis.

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

Vous pouvez supprimer le sommeil 1, c’est ici seulement pour éviter tout problème d’inondation au cas où l’hôte serait accessible mais que le ping ne se termine pas avec le code 0.

rayon
la source
4

S'il vous plaît voir de bonnes options à stackoverflow . Voici un exemple dans bash, vous devrez parcourir le code suivant jusqu’à ce qu’il retourne un résultat ping réussi.


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

François Wolmarans
la source
3

N'importe laquelle des boucles ci-dessus peut également être utilisée avec fping plutôt qu'avec ping, qui, IMO, convient mieux à une utilisation dans des scripts que le ping lui-même. Voir fping (1) pour plus de détails.

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

également utile pour tester si les machines sont en marche avant de faire quelque chose dessus. Un exemple simple:

pour h dans HOST1 HOST2 HOST3; faire
  si fping -q $ h; ensuite
     echo -n "$ h:"
     ssh $ h "uname -a"
  Fi
terminé
cas
la source
1

Cela va essayer un nombre de fois donné.

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

Au lieu de faire écho $r, vous pouvez le tester et agir en fonction de sa valeur:

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

Pour gérer correctement le ping SIGINT sur 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"

en tant que fonction

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
la source
0

J'ai utilisé la fonction suivante. J'aime ça parce que je peux lui dire d'arrêter d'essayer après un moment:

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

Il peut être utilisé comme ceci pour lancer quelque chose:

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

En général, je veux attendre que ma base de données ou un autre serveur apparaisse, mais je ne veux pas attendre trop longtemps. Le code suivant attend 10 secondes, puis définit le code de sortie si le serveur n'apparaît pas dans le délai imparti.

Si le serveur apparaît avant la limite de temps, la boucle sera court-circuitée afin que le prochain bit de code puisse être exécuté.

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

Une autre amélioration à la réponse de Gordon Davisson:

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

avec le '$ ()' environnant, un sous-shell est démarré et vous pouvez donc utiliser Control-C pour terminer la boucle si l'hôte n'est pas disponible.

Shawn  
la source