Como executar ping no linux até que o host seja conhecido?

46

Como posso executar ping em um determinado endereço e, quando encontrado, pare de executar o ping.

Eu quero usá-lo em um script bash, portanto, quando o host está inicializando, o script continua pingando e, a partir do momento em que o host está disponível, o script continua ...

Sander Versluys
fonte

Respostas:

84

Uma simplificação adicional da resposta de Martynas:

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

observe que o próprio ping é usado como teste de loop; assim que for bem-sucedido, o loop termina. O corpo do loop está vazio, com o comando nulo " :" usado para evitar um erro de sintaxe.

Atualização: Eu pensei em uma maneira de fazer o Control-C sair do loop de ping de forma limpa. Isso executará o loop em segundo plano, interceptará o sinal de interrupção (Control-C) e matará o loop em segundo plano, se ocorrer:

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"

É um pouco tortuoso, mas se você quiser que o loop seja cancelável, ele deve fazer o truque.

Gordon Davisson
fonte
6
Para adicionar 'suspensão' (por exemplo, a cada 5 segundos): while! ping -c1 www.google.com &> / dev / null; dorme 5; done
Lepe
4
Por padrão ping, aguarde 10 segundos antes de desistir de seu ping. Se você deseja reduzir isso para 1 segundo, pode usar -w1.
Jack O'Connor
2
@ JackO'Connor Usando ping-BSD, este é um capital-W1
Luke Exton
Meu único problema com esta resposta é que ela não lida bem com o SIGINT. Você não pode parar isso na linha de comando, se ele nunca for conectado por qualquer motivo.
Luke Exton
@LukeExton Isso se deve ao modo como o bash e o ping lidam com o SIGINT e como eles interagem (consulte esta pergunta ). Não tenho uma solução muito boa, mas há um kluge: use Control-Z para interromper o script e depois kill %1matá-lo.
Gordon Davisson
25

Você pode fazer um loop, enviar um ping e, dependendo do status, interromper o loop, por exemplo (bash):

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

Colocar isso em algum lugar do seu script irá bloquear, até que www.google.comseja pingável.

Martynas Saint
fonte
2
Este while truee breaké a solução mais limpa, IMO.
21119 Dan Carley
1
@ DanCarley Vou discordar de você pelo motivo de que, na resposta aceita, a versão de comando nula, pode-se substituir um sono / espera para interromper sua CPU e, nesse caso, eu a chamaria de solução mais limpa. O outro problema com esta resposta é que exige que o leitor / usuário entenda como o && funciona e como se o primeiro comando falhar, ele não será chamado. Esta é apenas uma opinião, como a sua.
Hamid
1
A principal diferença que vejo entre essa solução e a aceita é que ela ecoará a mensagem de erro "host desconhecido ..." até ser encontrada. Para adicionar sono (por exemplo, a cada 5 segundos):while true; do sleep 5; ping ...
lepe 10/04
20

Eu sei que a pergunta é antiga ... e especificamente pergunta a respeito ping, mas eu queria compartilhar minha solução.

Eu uso isso ao reiniciar hosts para saber quando posso voltar a SSH para eles novamente. (Como pingresponderá por alguns segundos antes de sshdiniciar.)

until nc -vzw 2 $host 22; do sleep 2; done
Aaron Copley
fonte
2
Foi exatamente isso que procurei, obrigado! Você pode até interromper a chamada com CTRL + C, o que não é o caso de algumas outras soluções nesse segmento.
Alex
1
Observe que isso funciona para versões BSD do netcat. A versão do nmap.org nas distribuições do Linux é implementada de maneira diferente, portanto a opção -z não existe e a opção -w aguarda uma conexão, mas não fecha quando for bem-sucedida. Funciona muito bem no OSX, no entanto.
Paul
É por isso que você não para na primeira resposta (ótima). Esta é a resposta para o problema real .
Leo
11

Faça ping no host de destino uma vez. Verifique se o ping foi bem-sucedido (o valor de retorno do ping é zero). Se o host não estiver ativo, execute ping novamente.

O código a seguir pode ser salvo como um arquivo e chamado com o nome do host como argumento ou retirado da primeira e da última linha e usado como função em um script existente (waitForHost hostname).

O código não avalia a causa da falha se o ping não resultar em uma resposta, fazendo um loop para sempre se o host não existir. Minha página de manual do BSD lista o significado de cada valor de retorno, enquanto o linux não, então acho que isso pode não ser portátil, por isso deixei de fora.

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

Você pode remover o sono 1, está aqui apenas para evitar qualquer problema de inundação, caso o host possa ser acessado, mas o ping não sairá com o código 0.

raio
fonte
4

Por favor, veja boas opções em stackoverflow . Aqui está um exemplo no bash, você terá que repetir o código a seguir até que ele retorne um resultado de ping com êxito.


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

qualquer um dos loops acima também pode ser usado com fping em vez de ping, o que, como IMO, é mais adequado para uso em scripts do que o próprio ping. Veja fping (1) para detalhes.

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

também é útil para testar se as máquinas estão funcionando antes de fazer algo nelas. Um exemplo simples:

para h em HOST1 HOST2 HOST3; Faz
  se fping -q $ h; então
     eco -n "$ h:"
     ssh $ h "uname -a"
  fi
feito
cas
fonte
1

Isso tentará um determinado número de vezes.

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

Em vez de ecoar $r, você pode testá-lo e agir de acordo com seu valor:

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

Para lidar bem com o ping do SIGINT no 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 uma função

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

Eu tenho usado a seguinte função. Gosto porque posso dizer para parar de tentar depois de um tempo:

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

Pode ser usado assim para iniciar algo:

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

Em geral, quero esperar que meu banco de dados ou outro servidor seja exibido, mas não quero esperar muito . O código a seguir aguarda 10 segundos e define o código de saída se o servidor não aparecer dentro do prazo.

Se o servidor aparecer antes do prazo, o loop será curto-circuito para que o próximo bit de código possa ser executado.

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

Um aprimoramento adicional à resposta de Gordon Davisson:

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

com o '$ ()' circundante, um subshell é iniciado e, portanto, você pode usar Control-C para finalizar o loop no caso de o host não ficar disponível.

Shawn  
fonte