Назад | Перейти на главную страницу

Bash-скрипт - дождитесь завершения всех процессов xargs

Я написал небольшой сценарий 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.