package main import ( "bytes" "fmt" "net" "os" "os/exec" "sort" "strings" "sync" "time" ) // PingResult holds the result of a ping operation type PingResult struct { IP net.IP Message string } // parseIP parses the string IP to net.IP func parseIP(ipStr string) net.IP { return net.ParseIP(ipStr) } // pingIP pings an IP address and sends a PingResult to the results channel. func pingIP(ipStr string, wg *sync.WaitGroup, results chan<- PingResult) { defer wg.Done() ip := parseIP(ipStr) cmd := exec.Command("ping", "-c", "3", "-W", "5", ipStr) if err := cmd.Run(); err != nil { results <- PingResult{IP: ip, Message: fmt.Sprintf("\x1b[0m%s\x1b[0m is \x1b[1m\x1b[31mdown\x1b[0m", ipStr)} } else { results <- PingResult{IP: ip, Message: fmt.Sprintf("\x1b[1m%s\x1b[0m is \x1b[1m\x1b[32mup\x1b[0m", ipStr)} } } func main() { if len(os.Args) < 2 { fmt.Println("Usage: chkip ...") return } var wg sync.WaitGroup results := make(chan PingResult, len(os.Args)-1) // Start the spinner in a goroutine stopSpinner := make(chan struct{}) go func() { spinner := []rune{'-', '\\', '|', '/'} i := 0 for { select { case <-stopSpinner: return default: fmt.Printf("\rPlease wait... %c", spinner[i%len(spinner)]) i++ time.Sleep(200 * time.Millisecond) } } }() // Start a goroutine for each IP address. for _, ipStr := range os.Args[1:] { wg.Add(1) go pingIP(ipStr, &wg, results) } // Close the results channel once all goroutines have finished. go func() { wg.Wait() close(results) fmt.Printf("\r%s\r", strings.Repeat(" ", 16)) // Use enough spaces to cover the expected line length }() // Collect results pingResults := make([]PingResult, 0, len(os.Args)-1) for result := range results { pingResults = append(pingResults, result) } // Sort results based on IP address sort.Slice(pingResults, func(i, j int) bool { return bytes.Compare(pingResults[i].IP, pingResults[j].IP) < 0 }) // Print sorted results for _, result := range pingResults { fmt.Println(result.Message) } }