Как остановить xargs от плохого слияния вывода из нескольких процессов?

17

Я использую xargsс опцией --max-args=0(альтернативно -P 0).

Однако выходные данные процессов объединяются в stdoutпоток без учета правильного разделения строк. Поэтому я часто получаю такие строки:

<start-of-line-1><line-2><end-of-line-1>

Как я использую egrepс ^в моем шаблоне на всей xargsпродукции этого Мессинг мой результат.

Есть ли какой-нибудь способ заставить xargsзаписывать выходные данные процесса по порядку (в любом порядке, если выходные данные одного процесса непрерывны)?

Или какое-то другое решение?

Изменить: более подробную информацию о сценарии использования:

Я хочу загружать и анализировать веб-страницы с разных хостов. Поскольку загрузка каждой страницы занимает около секунды, а есть несколько десятков страниц, я хочу распараллелить запросы.

Моя команда имеет следующую форму:

echo -n $IPs | xargs --max-args=1 -I {} --delimiter ' ' --max-procs=0 \
wget -q -O- http://{}/somepage.html | egrep --count '^string'

Я использую bash, а не что-то вроде Perl, потому что IP-адреса хоста (переменная $ IPs) и некоторые другие данные поступают из включенного файла bash.

Кристоф Вурм
источник
Можете ли вы привести более полный пример к вашему вопросу? Не ясно, как или почему вы используете в настоящее время xargs.
Калеб
Решение этой проблемы будет непростым: необходимо использовать разные файловые дескрипторы для вывода каждого процесса и использовать небольшой сервер для сбора строк. xargsкажется, не предоставляет такую ​​функцию.
Стефан Гименес
@Caleb Вот, пожалуйста, надеюсь, это поможет :-)
Кристоф Вурм
Определенно не легкое решение, но, возможно, вы могли бы использовать makeфункцию заданий, я думаю, что makeобъединяет выходные строки правильно.
Стефан Гименес
делает добавление --line-bufferedфлага, чтобы egrepпомочь
iruvar

Ответы:

6

Это должно сделать трюк:

echo -n $IPs | xargs --max-args=1 -I {} --delimiter ' ' --max-procs=0 \
  sh -c "wget -q -O- 'http://{}/somepage.html' | egrep --count '^string'" | \
  { NUM=0; while read i; do NUM=$(($NUM + $i)); done; echo $NUM; }

Идея здесь состоит в том, чтобы сделать отдельные подсчеты и суммировать их в конце. Может потерпеть неудачу, если отдельные подсчеты достаточно велики, чтобы их можно было смешать, но это не должно иметь место.

Стефан Хименес
источник
14

GNU Parallel специально разработан для решения этой проблемы:

echo -n $IPs | parallel -d ' ' -j0 wget -q -O- http://{}/somepage.html | egrep --count '^string'

Если ваши IP-адреса находятся в файле, это еще красивее:

cat IPs | parallel -j0 wget -q -O- http://{}/somepage.html | egrep --count '^string'

Чтобы узнать больше, посмотрите вступительное видео: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Оле Танге
источник
2
Хороший инструмент! Кроме того, я держу пари, что кто-то скажет вам, что кошка очень бесполезна очень скоро.
Стефан Гименес
1
Я знаю. Но мне легче читать, и я обычно работаю на 48-ядерных машинах, поэтому несколько дополнительных тактов для одного из незанятых ядер все еще остаются проблемой.
Оле Танге
параллель была бы идеальной для работы, если бы она была в репозиториях Debian.
Кристоф Вурм
1
@Legate Debian включает в себя parallelкоманду moreutils , которой здесь достаточно:parallel -j99 -i sh -c 'wget -q -O- http://{}/somepage.html | egrep -c "^string"' -- $IPs
Жиль "ТАК - прекрати быть злым"
@Legate фотографии build.opensuse.org/package/... для файла .deb и bugs.debian.org/cgi-bin/bugreport.cgi?bug=518696 для ошибки в толчке.
Оле Танге