วิธี ping ใน linux จนกว่าโฮสต์จะรู้


46

ฉันจะส่ง Ping ไปยังที่อยู่ที่แน่นอนได้อย่างไรและเมื่อพบให้หยุดส่ง Ping

ฉันต้องการใช้มันในสคริปต์ทุบตีดังนั้นเมื่อโฮสต์เริ่มต้นสคริปต์จะยังคงกระตุกและจากช่วงเวลาที่โฮสต์พร้อมใช้งานสคริปต์จะดำเนินต่อไป ...

คำตอบ:


84

ความเรียบง่ายเพิ่มเติมของคำตอบของ Martynas:

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

โปรดทราบว่าการ ping นั้นใช้เป็นการทดสอบลูป ทันทีที่มันประสบความสำเร็จลูปจะสิ้นสุดลง วนรอบร่างกายว่างเปล่าโดยใช้คำสั่ง null " :" เพื่อป้องกันข้อผิดพลาดทางไวยากรณ์

อัปเดต: ฉันคิดถึงวิธีที่จะทำให้ Control-C ออกจากลูปปิงอย่างหมดจด สิ่งนี้จะเรียกใช้ลูปในพื้นหลังดักสัญญาณ interrupt (Control-C) และฆ่าลูปพื้นหลังหากเกิดขึ้น:

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"

มันค่อนข้างจะเป็นวงจร แต่ถ้าคุณต้องการยกเลิกการวนซ้ำ


6
ในการเพิ่ม 'sleep' (เช่นทุกๆ 5 วินาที): ในขณะที่! ping -c1 www.google.com &> / dev / null; นอน 5 เสร็จแล้ว
lepe

4
โดยค่าเริ่มต้นpingจะรอ 10 วินาทีก่อนที่จะยอมแพ้ ping หากคุณต้องการที่จะลดที่ 1 -w1วินาทีคุณสามารถใช้
Jack O'Connor

2
@ JackO'Connor การใช้ BSD ping นี่คือเมืองหลวง-W1
Luke Exton

ปัญหาเดียวของฉันสำหรับคำตอบนี้คือมันไม่สามารถจัดการ SIGINT ได้ดี คุณไม่สามารถหยุดสิ่งนี้ได้จากบรรทัดคำสั่งหากไม่สามารถเชื่อมต่อได้ด้วยเหตุผลใดก็ตาม
ลุคเอกซ์

@LukeExton นั่นเป็นเพราะวิธีทุบตีและ ping จัดการ SIGINT และวิธีที่พวกเขาโต้ตอบ (ดูคำถามนี้ ) ฉันไม่มีวิธีแก้ปัญหาที่ดีมาก แต่มี kluge: ใช้ Control-Z เพื่อหยุดสคริปต์แล้วkill %1ฆ่ามัน
Gordon Davisson

25

คุณสามารถทำลูปส่ง ping หนึ่งอันและขึ้นอยู่กับการแบ่งสถานะของลูปตัวอย่างเช่น (bash):

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

การวางตำแหน่งนี้ไว้ในสคริปต์ของคุณจะบล็อกจนกว่าwww.google.comจะสามารถทำได้


2
นี้while trueและbreakเป็นวิธีการแก้ทำความสะอาด, IMO
Dan Carley

1
@DanCarley ฉันจะไม่เห็นด้วยกับคุณด้วยเหตุผลว่าในคำตอบที่ยอมรับรุ่นคำสั่ง null หนึ่งสามารถทดแทนการนอนหลับ / รอเพื่อให้ CPU ของคุณหยุดพักและในกรณีที่ฉันจะเรียกมันว่าโซลูชั่นที่สะอาด ปัญหาอีกข้อหนึ่งของคำตอบนี้คือต้องการให้ผู้อ่าน / ผู้ใช้เข้าใจวิธีการทำงาน && และถ้าคำสั่งแรกล้มเหลวคำสั่งนั้นจะไม่ถูกเรียก นี่เป็นเพียงความเห็นเช่นเดียวกับคุณ
ฮามิด

1
ความแตกต่างหลักที่ฉันเห็นระหว่างโซลูชันนี้กับโซลูชันที่ยอมรับคือโซลูชันนี้จะสะท้อนข้อความแสดงข้อผิดพลาด "ไม่ทราบโฮสต์ ... " จนกว่าจะพบ ในการเพิ่มการนอนหลับ (เช่นทุกๆ 5 วินาที):while true; do sleep 5; ping ...
lepe

20

ฉันรู้ว่าคำถามนั้นเก่าแล้วและถามโดยเฉพาะเกี่ยวกับเรื่องpingนี้ แต่ฉันต้องการแบ่งปันวิธีแก้ปัญหาของฉัน

ฉันใช้สิ่งนี้เมื่อรีบูตเครื่องโฮสต์เพื่อทราบว่าเมื่อใดที่ฉันจะสามารถ SSH กลับเข้าไปในพวกเขาอีกครั้ง (เนื่องจากpingจะตอบสนองเป็นเวลาหลายวินาทีก่อนที่sshdจะเริ่ม)

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

2
นั่นคือสิ่งที่ฉันค้นหาขอบคุณ! คุณสามารถขัดจังหวะการโทรด้วย CTRL + C ซึ่งไม่ใช่กรณีสำหรับโซลูชันอื่น ๆ ในชุดข้อความนี้
Alex

1
หมายเหตุสิ่งนี้ใช้ได้กับ netcat เวอร์ชัน BSD เวอร์ชัน nmap.org ใน Linux distros มีการใช้งานที่แตกต่างกันดังนั้นจึงไม่มีตัวเลือก -z และตัวเลือก -w จะรอการเชื่อมต่อ แต่จะไม่ปิดเมื่อประสบความสำเร็จ ใช้งานได้ดีใน OSX แม้ว่า
พอล

นี่คือเหตุผลที่คุณไม่หยุดตอบคำถามแรก (ละเอียด) นี่คือคำตอบของปัญหาจริง
ลีโอ

11

Ping โฮสต์เป้าหมายหนึ่งครั้ง ตรวจสอบว่าการ ping สำเร็จ (ค่าส่งคืนของ ping เป็นศูนย์) หากโฮสต์ไม่ได้อยู่ให้ปิงอีกครั้ง

รหัสต่อไปนี้สามารถบันทึกเป็นไฟล์และเรียกใช้ด้วยชื่อโฮสต์เป็นอาร์กิวเมนต์หรือถอดจากบรรทัดแรกและบรรทัดสุดท้ายและใช้เป็นฟังก์ชันภายในสคริปต์ที่มีอยู่ (ชื่อโฮสต์ waitForHost)

รหัสไม่ได้ประเมินสาเหตุของความล้มเหลวหากการ ping ไม่ส่งผลให้เกิดการตอบสนองดังนั้นการวนซ้ำตลอดไปหากไม่มีโฮสต์อยู่ BSD manpage ของฉันแสดงความหมายของแต่ละค่าที่ส่งคืนในขณะที่ linux ไม่ได้ดังนั้นฉันเดาว่านี่อาจจะไม่ใช่แบบพกพานั่นคือเหตุผลที่ฉันทิ้งมันไว้

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

คุณสามารถลบ sleep 1 ได้ที่นี่เพื่อป้องกันปัญหาน้ำท่วมในกรณีที่โฮสต์สามารถเข้าถึงได้ แต่ ping จะไม่ออกจากด้วยรหัส 0


4

โปรดดูตัวเลือกที่ดีในStackOverflow นี่คือตัวอย่างใน bash คุณจะต้องวนซ้ำโค้ดต่อไปนี้จนกว่ามันจะส่งคืนผลลัพธ์การ 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


3

การวนรอบด้านบนใด ๆ ยังสามารถใช้กับ fping แทน ping ซึ่ง IMO เหมาะสำหรับการใช้ในสคริปต์มากกว่า ping เอง ดูfping (1)สำหรับรายละเอียด

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

ยังมีประโยชน์สำหรับการทดสอบว่าเครื่องจักรทำงานก่อนที่จะทำอะไรกับมัน ตัวอย่างง่ายๆ:

สำหรับ h ใน HOST1 HOST2 HOST3; ทำ
  ถ้า fping -q $ h; แล้วก็
     echo -n "$ h:"
     ssh $ h "uname -a"
  Fi
เสร็จแล้ว

1

วิธีนี้จะลองตามจำนวนครั้งที่กำหนด

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

แทนการสะท้อน$rคุณสามารถทดสอบและปฏิบัติตามค่าของมัน:

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

1

เพื่อจัดการ SIGINT บน 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"

เป็นฟังก์ชั่น

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

ฉันใช้ฟังก์ชั่นต่อไปนี้แล้ว ฉันชอบเพราะฉันสามารถบอกได้ว่าให้หยุดพยายามอีกสักครู่:

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

มันสามารถใช้สิ่งนี้เพื่อเปิดบางสิ่ง:

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

0

โดยทั่วไปฉันต้องการรอให้ฐานข้อมูลหรือเซิร์ฟเวอร์อื่น ๆ ของฉันมา แต่ฉันไม่ต้องการรอนานเกินไป รหัสต่อไปนี้รอเป็นเวลา 10 วินาทีจากนั้นตั้งรหัสออกหากเซิร์ฟเวอร์ไม่ปรากฏภายในเวลาที่กำหนด

หากเซิร์ฟเวอร์ปรากฏก่อนกำหนดเวลาลูปจะถูกลัดวงจรเพื่อให้สามารถเรียกใช้โค้ดถัดไปได้

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

0

การปรับปรุงเพิ่มเติมสำหรับคำตอบของ Gordon Davisson:

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

ด้วยการล้อมรอบ '$ ()' จะมีการเริ่มต้น subshell ดังนั้นคุณสามารถใช้ Control-C เพื่อยุติการวนซ้ำในกรณีที่โฮสต์ไม่สามารถใช้งานได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.