#!/bin/bash # quickGetPing - How to collect many ping's outputs into bash variables # (C) 2025 Felix Hauri - felix@f-hauri.ch # Licensed under terms of GPL v3. www.gnu.org # This script is intented to be used under GNU/Linux, as they use kernel # pseudo filesystem /proc (only in `getArps` function). # Collecting networks IPv4 status and infos from parallelized ping's answer, # into three differents bash arrays: # - $listHosts Associative array: ([hosta]='10.2.3.45' [hostb]='10.2.3.46'... # - $byIp Indexed array: ([167904045]='hosta' [167904046]='hostb'... # - $stateList Integer idexed array: ([167904045]='1' [167904046]='0'... # Note: In order to avoid bash loops, all array operation are done by "mapping" # ( While keeping in mind `declare -a "$str"` is like an `eval`!! ) # In a second operation, variable "$listArps" are built with command: # mapfile [ip or hostname] [ip or hostname]... # Something like: quickGetPing $(awk '/^[1.9]/{if($3)print $3}' > 24 }") printf -v __tmp_str "$__tmp_str" ${__tmp_int[@]} local -ai __tmp_int=("${@/*/& >> 16 \& 255}") printf -v __tmp_str "$__tmp_str" ${__tmp_int[@]} local -ai __tmp_int=("${@/*/& >> 8 \& 255}") printf -v __tmp_str "$__tmp_str" ${__tmp_int[@]} local -ai __tmp_int=("${@/*/& \& 255}") printf -v __tmp_str "$__tmp_str" ${__tmp_int[@]} if [[ $__out_var ]]; then mapfile -t "$__out_var" <<<"${__tmp_str%$'\n'}" else echo "${__tmp_str//$'\n'/ }" fi } ip2int() { # Convert array of IPv4 to array of integer, by mapping if [[ $1 == -v ]]; then local __out_var="$2" shift 2 else local __out_var= fi set -- "${@/./<<24|}"; set -- "${@/./<<16|}"; set -- "${@/./<<8|}" local -ai res=("$@") if [[ $__out_var ]]; then mapfile -d\ -t "$__out_var" <<<"${res[*]}" else echo "${res[*]}" fi } checkIPv4() { # Work in progress, not used in this script. local __args_array=("$@") __tmp_str printf -v __tmp_str '[%s]= ' ${__args_array[*]//[0-9]} local -A __check_Aarray="($__tmp_str)" (( ${#__check_Aarray[@]} == 1 )) && [[ ${!__check_Aarray[*]} == ... ]] || return 1; __args_array=(${__args_array[*]//[12][0-9][0-9]/.}) __args_array=(${__args_array[*]//[0-9][0-9]/.}) printf -v __tmp_str '[%s]= ' ${__args_array[*]//[0-9]/.} local -A __check_Aarray="($__tmp_str)" (( ${#__check_Aarray[@]} == 1 ))&& [[ ${!__check_Aarray[*]} == ....... ]]|| return 1 printf -v __tmp_str ' %d > 255 || ' ${*//./ } return $(($__tmp_str 0)) } runPPing () { # This will create 3 array variables by using SDTOUT and 2 more FDs in # backgrounded task (sed) who will send separatedly, required output # to specific FD. local -i hstFd byIpFd local str exec {hstFd}<> <(:); exec {byIpFd}<> <(:); local -ai upList="($( sed -une ' /PING \(.*\) (\([0-9.]\+\)) 56.*/{ s//[\1]=\2 /; w /dev/fd/'$hstFd -e ' /\[\(.*\)\]=\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\) $/{ s//[\2<<24|\3<<16|\4<<8|\5]="\1" /;w /dev/fd/'$byIpFd -e ' }; }; /^64.*(\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)):.*/{ s//[\1<<24|\2<<16|\3<<8|\4]=1 /p }; /^64 .* from \([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)[^)]*/{ s//[\1<<24|\2<<16|\3<<8|\4]=1 /p }; ' < <( for hst; do # in ${hosts[@]}; do ping -c$numPing -W1 $hst & done wait )))" printf '\1' >&$hstFd read -d$'\1' -u $hstFd str exec {hstFd}>&- declare -gA "listHosts=(${str//$'\n'})" printf '\1' >&$byIpFd read -d$'\1' -u $byIpFd str exec {byIpFd}>&- declare -ga "byIp=(${str//$'\n'})" printf -v str '[%s]=0 ' ${!byIp[@]} declare -gai "stateList=($str)" printf -v str '[%d]+=1 ' ${!upList[@]} declare -gai "stateList+=($str)" } getArps() { local arpList arpCleanedList str ips mapfile -t arpList