Bagaimana cara ping di linux sampai host diketahui?

46

Bagaimana saya bisa melakukan ping ke alamat tertentu dan ketika ditemukan, berhentilah melakukan ping.

Saya ingin menggunakannya dalam skrip bash, jadi ketika host memulai, skrip terus melakukan ping dan sejak host tersedia, skrip berlanjut ...

Sander Versluys
sumber

Jawaban:

84

Penyederhanaan lebih lanjut dari jawaban Martynas:

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

perhatikan bahwa ping itu sendiri digunakan sebagai tes loop; begitu berhasil, loop berakhir. Badan loop kosong, dengan perintah " :" nol digunakan untuk mencegah kesalahan sintaks.

Pembaruan: Saya memikirkan cara untuk membuat Control-C keluar dari loop ping dengan bersih. Ini akan menjalankan loop di latar belakang, menjebak sinyal interrupt (Control-C), dan membunuh loop latar belakang jika terjadi:

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"

Agak berputar-putar, tetapi jika Anda ingin loop dapat dibatalkan itu harus melakukan trik.

Gordon Davisson
sumber
6
Untuk menambahkan 'tidur' (mis. Masing-masing 5 detik): sementara! ping -c1 www.google.com &> / dev / null; tidur 5; selesai
lepe
4
Secara default pingakan menunggu 10 detik sebelum menyerah pada pingnya. Jika Anda ingin mengurangi itu menjadi 1 detik, Anda dapat menggunakannya -w1.
Jack O'Connor
2
@ JackO'Connor Menggunakan ping BSD, ini adalah modal-W1
Luke Exton
Satu-satunya masalah saya dengan jawaban ini adalah tidak menangani SIGINT dengan baik. Anda tidak dapat menghentikan ini dari baris perintah, jika tidak akan terhubung dengan alasan apa pun.
Luke Exton
@LukeExton Itu karena cara bash dan ping menangani SIGINT, dan bagaimana mereka berinteraksi (lihat pertanyaan ini ). Saya tidak punya solusi yang sangat bagus, tetapi ada kluge: gunakan Control-Z untuk menghentikan skrip, lalu kill %1membunuhnya.
Gordon Davisson
25

Anda dapat melakukan loop, mengirim satu ping dan tergantung pada status break loop, misalnya (bash):

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

Menempatkan ini di suatu tempat di skrip Anda akan diblokir, sampai www.google.comdapat diputuskan.

Martynas Saint
sumber
2
Ini while truedan breakmerupakan solusi bersih, IMO.
Dan Carley
1
@DanCarley Saya akan tidak setuju dengan Anda karena alasan bahwa dalam jawaban yang diterima, versi perintah nol, orang dapat mengganti waktu tidur / menunggu untuk memberikan CPU Anda istirahat, dan dalam hal ini saya akan menyebutnya solusi bersih. Masalah lain dengan jawaban ini, adalah bahwa ia membutuhkan pembaca / pengguna untuk memahami bagaimana && bekerja, dan bagaimana jika perintah pertama gagal, itu tidak akan dipanggil. Ini hanya sebuah opini, seperti pendapat Anda sendiri.
Hamid
1
Perbedaan utama yang saya lihat antara solusi ini dan yang diterima, adalah bahwa ini akan mengulang pesan kesalahan "host tidak dikenal ..." sampai ditemukan. Untuk menambah tidur (mis. Masing-masing 5 detik):while true; do sleep 5; ping ...
lepe
20

Saya tahu pertanyaannya sudah lama ... dan secara khusus menanyakan ping, tetapi saya ingin membagikan solusi saya.

Saya menggunakan ini ketika me-reboot host untuk mengetahui kapan saya bisa SSH kembali ke mereka lagi. (Karena pingakan merespons selama beberapa detik sebelum sshddimulai.)

until nc -vzw 2 $host 22; do sleep 2; done
Aaron Copley
sumber
2
Itulah tepatnya yang saya cari, terima kasih! Anda bahkan dapat menginterupsi panggilan dengan CTRL + C yang tidak berlaku untuk beberapa solusi lain di utas ini.
Alex
1
Perhatikan ini berfungsi untuk versi BSD dari netcat. Versi nmap.org di distro Linux diimplementasikan secara berbeda, sehingga opsi -z tidak ada, dan opsi -w menunggu koneksi tetapi tidak menutup ketika berhasil. Berfungsi bagus di OSX.
Paul
Inilah sebabnya mengapa Anda tidak berhenti pada jawaban pertama (baik). Inilah jawaban untuk masalah sebenarnya .
Leo
11

Ping host target sekali. Periksa apakah ping berhasil (nilai balik ping adalah nol). Jika host tidak hidup, ping lagi.

Kode berikut dapat disimpan sebagai file dan dipanggil dengan nama host sebagai argumen, atau dilucuti dari baris pertama dan terakhir dan digunakan sebagai fungsi dalam skrip yang ada (waitForHost hostname).

Kode tidak mengevaluasi penyebab kegagalan jika ping tidak menghasilkan respons, sehingga berulang selamanya jika host tidak ada. Manual BSD saya mencantumkan arti dari masing-masing nilai kembali, sedangkan yang linux tidak, jadi saya kira ini mungkin tidak portabel, itu sebabnya saya meninggalkannya.

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

Anda dapat menghapus sleep 1, itu hanya di sini untuk mencegah masalah banjir jika tuan rumah dapat dijangkau tetapi ping tidak akan keluar dengan kode 0.

radius
sumber
4

Silakan lihat opsi yang baik di stackoverflow . Berikut ini contoh dalam bash, Anda harus mengulang kode berikut hingga mengembalikan hasil ping yang berhasil.


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

salah satu loop di atas juga dapat digunakan dengan fping daripada ping yang, IMO, lebih cocok untuk digunakan dalam skrip daripada ping itu sendiri. Lihat fping (1) untuk detailnya.

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

juga berguna untuk menguji apakah mesin sudah bangun sebelum melakukan sesuatu pada mereka. Contoh sederhana:

untuk h di HOST1 HOST2 HOST3; melakukan
  jika fping -q $ h; kemudian
     echo -n "$ h:"
     ssh $ h "uname -a"
  fi
Selesai
cas
sumber
1

Ini akan mencoba beberapa kali.

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

Alih-alih menggema $r, Anda dapat mengujinya dan bertindak sesuai nilainya:

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

Untuk menangani SIGINT dengan baik pada 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"

sebagai fungsi

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

Saya telah menggunakan fungsi berikut. Saya suka karena saya bisa mengatakan itu untuk berhenti mencoba setelah beberapa saat:

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

Dapat digunakan seperti ini untuk meluncurkan sesuatu:

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

Secara umum saya ingin menunggu database atau server lain muncul, tetapi saya tidak ingin menunggu terlalu lama. Kode berikut menunggu selama 10 detik, kemudian menetapkan kode keluar jika server tidak muncul dalam batas waktu.

Jika server muncul sebelum batas waktu, loop akan dihubung pendek sehingga bit kode berikutnya dapat berjalan.

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

Peningkatan lebih lanjut untuk jawaban Gordon Davisson:

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

dengan '$ ()' di sekitarnya, sebuah subkulit dimulai dan oleh karena itu Anda dapat menggunakan Control-C untuk mengakhiri loop jika host tidak tersedia.

Shawn  
sumber