... && ((++ALIVE)) && ... &
Это выражение выполняется внутри другого процесса, поэтому изменения не отображаются в родительском процессе
a=1
((++a)) & # <- is run as another process
echo "$a" # this will print 1 ...
(
((++a))
echo "$a"
) & # this will print 2 in the background
wait
Итак, мы хотим запустить (( $3 - $2 ))
процессов. Каждый из этих процессов будет выполняться одновременно. Нам нужно получить результат от всех этих процессов в конце. Мы приходим к тому, что мы называем «синхронизацией». Нам нужно синхронизировать все значения всех процессов в одной точке.
Мы можем представить, используя экс. 255 файлов, один файл уникален для каждого процесса. Затем после выполнения childs мы можем запросить файлы.
Проще всего использовать стандартный вывод или другой поток с буферизацией строки:
live_hosts=$(
for ((i = $2; i <= $3 && i <= 254; ++i)); do
# `if` is more readable then `a && b`
(
if ping -c 1 -i 0.2 -w 1 -W 1 "$1.$i" >/dev/null; then
echo "$1.$i"
fi
) &
done
wait # remember to wait for all the childs
)
Поскольку stdout должен быть буферизованной строкой, кратное число echo "$1.$i"
не должно перехватывать запись, поэтому мы должны получить только переменную со строками. Тогда вы можете просто:
echo "There were $(printf "$live_hosts" | wc -l) online hosts"
Но мы могли бы сделать это с помощью временного каталога:
tmpdir=$(mktemp -d)
for ((i = $2; i <= $3 && i <= 254; ++i)); do
(
if ping -c 1 -i 0.2 -w 1 -W 1 "$1.$i" >/dev/null; then
# create a file with the name "$i" inside tmpdir
# I don't think content matters (just the name of file)
touch "$tmpdir"/"$i"
fi
) &
done
wait
# ex. the count of alives are the count of files inside out tmpdir
alive=$(find "$tmpdir" -type f -print . | wc -c)
# this is funny
for i in "$tmpdir"/*; do
echo "$1.$i is alive!"
done
# remember to cleanup
rm -r "$tmpdir"
И просто для того, чтобы сделать это интересным, и, поскольку мы любим единомышленников, вот решение, использующее xargs
и seq
:
live_hosts=$(seq -f "$1.%.0f" "$2" "$3" | xargs -n1 -P0 -- sh -c 'ping -c 1 -i 0.2 -w 1 -W 1 "$1" >/dev/null && echo "$1"' --)
alive=$(echo "$live_hosts" | wc -l)
# well, if just the count matters, add the `| wc -l` to the one liner ..