Запуск скрипта цикла bash curl с помощью GNU Parallel

Совсем недавно начал программировать на bash и наткнулся на GNU Parallel, это как раз то, что мне нужно для моего проекта. Имейте базовый сценарий цикла, который предназначен для циклического просмотра списка IP-адресов и пинга каждый раз. Список с ip постоянно пополняется новыми, управляемыми другим скриптом.

Для многопоточности я хотел бы использовать GNU Parallel.

Моя идея состояла в том, чтобы запустить 10 экземпляров Parallel, каждый из которых будет захватывать один ip-адрес из списка, вставлять его в команду curl и удалять из списка, чтобы другие экземпляры не могли его подобрать.

#! /bin/bash
while true; do

while read -r ip; do
curl $ip >> result.txt
sed -i '1,1 d' iplist
done < ipslist
done

Я не уверен, как правильно запустить сценарий bash, в этом случае каждое решение, которое я мог найти, не работает должным образом, и все становится совершенно беспорядочным. У меня есть ощущение, что все это можно сделать с помощью одной строки, но по моим собственным причинам я бы предпочел запускать это как сценарий bash. Был бы признателен за любую помощь!


person Nikolas K    schedule 19.03.2018    source источник
comment
Вы используете это, чтобы проверить, какие хосты работают и обслуживают? Может быть, для этого проще использовать nmap, чем писать свой собственный. Я не уверен, что nmap действительно может выполнять HTTP-запросы, но достаточно просто проверить, что 80/TCP открыт.   -  person Thomas    schedule 19.03.2018
comment
Спасибо за предложение, я знаю о превосходстве nmap и других инструментов для многих задач, но для этого проекта мне нужно использовать curl   -  person Nikolas K    schedule 19.03.2018


Ответы (4)


Решение Томаса выглядит правильным для этой конкретной ситуации. Если же вам нужно сделать больше, чем просто curl, то я рекомендую сделать функцию:

#! /bin/bash

doit() {
  ip="$1"
  curl "$ip"
  echo do other stuff here
}
export -f doit

while true; do
  parallel -j10 doit < ipslist >> result.txt
done

Если вы хотите, чтобы ipslist была очередью, чтобы вы могли позже добавлять вещи в очередь, и вы хотите, чтобы она была curled только один раз:

tail -n+0 -f ipslist | parallel doit >> result.txt

Теперь вы можете позже просто добавить материал в ipslist, и GNU Parallel curl сделает и это.

(Существует небольшая проблема при использовании GNU parallel в качестве системы очередей/пакетного менеджера: вы должны отправить количество заданий JobSlot, прежде чем они начнутся, и после этого вы можете отправлять по одному, и задание начнется немедленно, если свободные слоты Выходные данные из запущенных или завершенных заданий задерживаются и будут напечатаны только тогда, когда JobSlots больше заданий было запущено (если вы не используете --ungroup или --line-buffer, в этом случае выходные данные из заданий печатаются немедленно) , Например, если у вас есть 10 слотов для заданий, то вывод первого завершенного задания будет распечатан только после запуска задания 11, а вывод второго завершенного задания будет напечатан только после запуска задания 12.)

person Ole Tange    schedule 21.03.2018

Это работает для меня:

#!/bin/bash

while true; do
  parallel -j10 curl '{}' < ipslist >> result.txt
done

Если это не то, что вы намеревались, пожалуйста, обновите свой вопрос, чтобы уточнить.

person Thomas    schedule 19.03.2018
comment
Хотя это выглядит элегантно и просто, я бы предпочел не использовать команду parallel из скрипта, а запускать скрипт с помощью parallel из терминала. Поскольку скрипт будет расширяться позже, было бы лучше сохранить его как чистый bash. Кроме того, я не понимаю, как ваше решение позволяет избежать повторного использования одной и той же строки, но я могу ошибаться. Мне нужно что-то вроде: parallel -n0 script.sh ::: {1..10} решение, но, по какой-то причине это просто не работает для меня. - person Nikolas K; 19.03.2018
comment
Пожалуйста, отредактируйте свой вопрос, чтобы уточнить, что именно вам нужно, и почему это решение не работает. - person Thomas; 19.03.2018
comment
@NikolasK Причина, по которой это не работает, скорее всего, в том, что вы одновременно читаете и редактируете один и тот же файл из нескольких процессов. Довольно сложно получить право, не имея состояния гонки. Также решение @Thomas, вероятно, быстрее, так как он не редактирует ipslist. - person Ole Tange; 21.03.2018
comment
@NikolasK Знаете ли вы, что вы можете встроить GNU Parallel в сценарий bash, используя --embed? Доступно с версии 20180222. - person Ole Tange; 21.03.2018

Я бы просто использовал xargs. Кажется, не многие люди знают об этом, но это гораздо больше, чем стандартное использование, чтобы просто сжать каждую строку ввода в одну строку. То есть это:

echo -e "A\nB\nC\nD\nE" | xargs do_something

по существу будет означать то же самое, что и это:

do_something A B C D E

Однако вы можете указать, сколько строк обрабатывается в одном чанке, используя опцию -L:

echo -e "A\nB\nC\nD\nE" | xargs -L2 do_something

будет переведено на:

do_something A B
do_something C D

Кроме того, вы также можете указать, сколько из этих фрагментов выполняется параллельно, с помощью параметра -P. Таким образом, чтобы обрабатывать строки одну за другой с параллелизмом, скажем, 3, вы должны сказать:

echo -e "A\nB\nC\nD\nE" | xargs -L1 -P3 do_something

И вуаля, у вас есть правильное параллельное выполнение с помощью основных инструментов Unix.

Единственная загвоздка в том, что вы должны убедиться, что вы разделяете выходы. Я не уверен, думали ли об этом раньше, но решение для случая curl выглядит примерно так:

cat url_list.txt | xargs -L1 -P10 curl -o paralell_#0.html

Где #0 будет заменено на cURL с извлеченным URL-адресом. Подробнее см. в руководствах:

person Dan    schedule 19.03.2018

Вы можете сделать это, и это сработает:

#! /bin/bash
while true; do

   while read -r ip; do
      curl $ip >> result.txt &
      sed -i '1,1 d' iplist
   done < ipslist
wait
done
person Matias Barrios    schedule 19.03.2018
comment
Если я проверю это в iplist с 1000000 IP-адресов, моя машина перестанет отвечать. - person Ole Tange; 21.03.2018