Я написал небольшой сценарий bash для сканирования XML-карты сайта URL-адресов. Он получает 5 URL-адресов параллельно с помощью xargs.
Теперь я хочу, чтобы электронное письмо было отправлено, когда все URL-адреса были просканированы, поэтому ему нужно дождаться завершения всех подпроцессов xargs, а затем отправить письмо.
Я пробовал использовать канал после xargs:
#!/bin/bash
wget --quiet --no-cache -O- http://some.url/test.xml | egrep -o "http://some.url[^<]+" | xargs -P 5 -r -n 1 wget --spider | mail...
и с wait
#!/bin/bash
wget --quiet --no-cache -O- http://some.url/test.xml | egrep -o "http://some.url[^<]+" | xargs -P 5 -r -n 1 wget --spider
wait
mail ...
И то, и другое не работает, письмо отправляется сразу после выполнения скрипта. Как я могу этого добиться? К сожалению, у меня нет parallel
программа на моем сервере (управляемый хостинг).
Вместо того, чтобы использовать xargs
, создать каждый wget
индивидуально в фоновом режиме и соберите PID фоновых процессов в список. Кроме того, убедитесь, что выходные данные фоновых процессов записываются в файл.
После того, как все фоновые процессы будут запущены, выполните все PID в списке и wait
каждый - уже вышедшие не будут блокироваться в wait
. Надеюсь, что после успешного ожидания всех фоновых процессов все, что осталось сделать, - это объединить выходные данные каждого фонового процесса в один файл и отправить его туда, где требуется выходной результат.
Что-то вроде (эхо, конечно, избыточно и только для демонстрационных целей):
#!/bin/bash
mail=$(tempfile)
pids=()
outputs=()
trap "rm -f ${outputs[@]}" EXIT
trap "rm -f $mail" EXIT
for url in $(wget --quiet --no-cache -O- http://some.url/test.xml |\
egrep -o "http://some.url[^<]+") ; do
output=$(tempfile)
wget --spider > $output 2>&1 &
pids+=($!)
outputs+=($output)
echo "Spawned wget and got PID ${pids[-1]}."
done
for pid in ${pids[@]} ; do
echo "Waiting for PID $pid."
wait $pid
done
# Concatenate outputs from individual processes into a single file.
for output in ${outputs[@]} ; do cat $output >> $mail ; done
# Mail that file.
< $mail mail -s "All outputs" some.user@some.domain
# end of file.