LINUX.ORG.RU

Как покрасивше сделать?

 


0

1

Это простой скрипт для проверки статусов страниц:

#!/bin/bash
SCRIPT_NAME=`basename "$0"`

usage()
{
  cat <<EOF
Get http status code for list of urls.

Usage: $SCRIPT_NAME [option] [INPUT]

Options:
  -h, --help: prints help and exit
  -w, --workers: number of workers (default: cpu cores x2)
EOF
}

WORKERS=$((`nproc --all` * 2))

ARGS=()
while (($#)); do
  case "$1" in
    -h|--help)
      usage
      exit 0;;
    -w|--workers)
      shift
      if [[ -z $1 ]]; then
        echo "number of workers is not specified" >&2
        exit 1
      fi
      WORKERS="$1";;
    *)
      ARGS+=("$1");;
  esac
  shift
done

# restore arguments. Я правильно вообще это делаю?
set -- "${ARGS[@]}"

if [[ -n $1 ]]; then
  URLS=`cat "$1"`
else
  URLS=`cat`
fi

# из-за проблем с шаблонами вызов curl пришлось обернуть функцией
_check_http_status_code()
{
  local url="$1"
  curl \
    -A "Mozilla/5.0 (X11; Linux x86_64; rv:90.0) Gecko/20100101 Firefox/90.0" \
    --retry 0 \
    -L \
    -m 3 \
    -o /dev/null \
    -s \
    -w '%{url_effective} %{response_code}\n' "$url"
}

export -f _check_http_status_code

# man parallel_tutorial
parallel -j "$WORKERS" _check_http_status_code '{}' <<< "$URLS"

Я давно не писал на баше «сурьезные» скрипты и чет по мне он слишком уродлив

★★

Последнее исправление: tz4678 (всего исправлений: 2)

Переписать на python. Bash уродлив по определению. Одна while (($#)); do чего стоит.

peregrine ★★★★★
()

Действительно перепиши лучше на python

XoFfiCEr ★★☆☆
()

Тебе херню советуют, перепеши на Си.

LINUX-ORG-RU ★★★★★
()

попробовать argparse + golang|python

anonymous
()

Не очень понятно, что конкретно тебе не нравится. Скрипт как скрипт. Работает и ладно. Вроде в нём всё понятно.

Legioner ★★★★★
()
Ответ на: комментарий от cobold

Что за parallel? Есть же посконный xargs.

Параллельное выполнение на bash легко программируется и это будет быстрее работать, так как в данном случае вызывается функция bash. Но если с функцией не извращаться, а вызывать то, что у него единственное: curl с аргументами, то xagrs подойдёт хорошо.

vodz ★★★★★
()

Как покрасивше сделать?

Просто сделай без баша.

crutch_master ★★★★★
()

подумаешь не красиво - главное что бы работало и делало это как можно быстрее… если переписать на питон или еще чего станет быстрее? если станет - переписывай.

anonymous
()
Ответ на: комментарий от anonymous

не станет, наоборот будет медленее. эта ползучая гнида еще все 16 гигов памяти на ноуте сожрет

tz4678 ★★
() автор топика
Ответ на: комментарий от anonymous

есть вариант написать для nmap скрипт на lua, но это дерьмо еще хуже баша

tz4678 ★★
() автор топика
Ответ на: комментарий от tfeartx

Это не костылить, это в явном виде задавать желаемое поведение. Да было бы здорово иметь ключ ignore-errors или что-то в этом духе. Но потом захочется игнорировать все ошибки кроме кода, 8, например. Опять придётся костылить

cobold ★★★★★
()
Ответ на: комментарий от Harald

а если идут усложнения, то красота в сложности?

anonymous
()

Почему потерли сообщение про MH17? Неужели обидел кому-то?(

Там же ссылка на топовую книгу оформленную в латехе, между прочим!

anonymous
()
Ответ на: комментарий от tz4678

эта ползучая гнида еще все 16 гигов памяти на ноуте сожрет

Да схрена бы?

Но, если очень тянет преписать на ЯП общего назначения, то всё рано нужно сделать это на Go.

Ты, кстати, уверен, что вызов _check_http_status_code будет работать везде? Вроде, нужно заэнфорсить баш в качестве дефолтного шелла для дочернего процесса, иначе тыква. Или у parallel и так жесткая привязка к баш?

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

Да схрена бы?

При использовании multiprocessing, десятками гигабайт память жрал.

Запуск интерпретатора, а потом с помощью этого интерпретатора выполнение байткода (в первый раз происходит происходит компиляция) НЕ МОЖЕТ работать быстрее чем чтение инструкций процессора с диска (parallel, curl и пр) в память и их выполнение

у меня дефолтный zsh.

tz4678 ★★
() автор топика

Лучше посоветуйте, как сделать чтоб parallel сожрал список в 100млн строк хотя бы и не умер. Или чем его заменить, а то он tmpdir хочет для пустых временных файлов зачем-то и --compress ещё, но все равно валится. xargs не подходит (или я неправильно его юзаю, выше в треде писал про костыли).

Короче, как можно распараллелить однострочник на n потоков, если на входе (возьмём задачу как у автора треда) этих урлов очень много?

Оно сейчас работает через

cat urls | parallel -j 100500 ./go.sh
, но хочется нормально.

tfeartx
()
Последнее исправление: tfeartx (всего исправлений: 2)
Ответ на: комментарий от tfeartx

так там наверное stackoverflow происходит. на go ожно что-нибудь накостылить либо nuclei использовать или nmap

tz4678 ★★
() автор топика
Ответ на: комментарий от tz4678

С памятью у питончика всё очень хорошо, а то, что тормозит, вопросов нет, это просто факт.

Но, вообще, так тебе воркеры на самом деле не нужны, в питоне ты бы сделал запросы асинхронно. Результат был бы заметно быстрее.

WitcherGeralt ★★
()
Ответ на: комментарий от tz4678

stackoverflow происходит

Нет, там parallel пишет что не может обработать столько аргументов и вообще спавнит много копий себя, лол.

tfeartx
()
Ответ на: комментарий от tfeartx
for i от 0 до ceil(arr_len / 1000)
  start_index = i * 1000
  last_index = min(start_index + 1000, arr_len)
  slice = срез data со start_index до last_index
  parallel ... <<< "$slice"

в питоне на чанки так разбить можно:

data = [i for i in range(10003)]
for i in range(0, len(data), 1000):
  batch = data[i:i+1000]
  # делай с ним что хочешь
tz4678 ★★
() автор топика
Последнее исправление: tz4678 (всего исправлений: 3)
Ответ на: комментарий от tz4678

Я понимаю. Но ведь речь идёт об абстрактной задаче с использованием parallel и все. Зачем он тогда нужен, если под него костылить нужно ещё больше, чем с xargs (с которым кстати эта конкретная задача с курлом решается без разбития входных данных на куски)?

tfeartx
()
Ответ на: комментарий от tfeartx

Если памяти дохрена:

import requests as req, multiprocessing as mp 

urls = [...]

def handle_url(url: str):
  try:
    r = req.get(url)
  except: pass
  # return None

with mp.Pool(processes=10) as p:
  results = p.map(handle_url, urls)
  # Отбросим все None
  results = filter(None, results)
  list(results) # у нас генератор, а не список
tz4678 ★★
() автор топика

по мне он слишком уродлив

Чем именно? Опиши.

anonymous
()

Я давно не писал на баше «сурьезные» скрипты

не нужно на баше писать серьёзные скрипты

using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using CommandLine;

namespace development16453699
{
    class Program
    {
        public class Options
        {
            [Option(shortName: 'w', longName: "workers", Required = false, HelpText = "number of workers (default: cpu cores x2)")]
            public int Workers { get; set; }
            
            [Value(index: 0, Required = true, HelpText = "String with urls separated by ';'")]
            public string Urls  { get; set; }
        }

        static void CheckUrl(string url)
        {
            try
            {	
                HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(url);
                wreq.UserAgent="Mozilla/5.0 (X11; Linux x86_64; rv:90.0) Gecko/20100101 Firefox/90.0";
                HttpWebResponse wres = (HttpWebResponse)wreq.GetResponse();
                Console.WriteLine($"Status Code of {url} is {(int)wres.StatusCode} {wres.StatusDescription}");
                wres.Close();
            }
            catch(WebException e)
            {
                Console.WriteLine("\n\n\nWebException Raised. The following error occurred : {0}",e.Status);
            }
            catch(Exception e)
            {
                Console.WriteLine("\n\n\nThe following Exception was raised : {0}",e.Message);
            }
        }

        static void Main(string[] args)
        {
            var parsedArguments = Parser.Default.ParseArguments<Options>(args);
            if (parsedArguments.Errors.Any()) return;
            int workers = parsedArguments.Value.Workers == 0 ? Environment.ProcessorCount * 2 : parsedArguments.Value.Workers;
            var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = workers };
            
            Parallel.ForEach(
                parsedArguments.Value.Urls.Split(';'),
                parallelOptions,
                url => { CheckUrl(url); }
            );
        }
    }
}
Ford_Focus ★★★★★
()
Ответ на: комментарий от Ford_Focus

сравни это с 20 строками на питоне:

import requests as req, multiprocessing as mp 
import sys

with open(sys.argv[1]) as fp:
  urls = fp.read().splitlines()

def handle_url(url: str):
  try:
    r = req.get(url)
    r.raise_for_status()
    return r.url
  except: 
    pass

with mp.Pool(processes=10) as p:
  results = p.map(handle_url, urls)
  results = filter(None, results)
  print('\n'.join(results))
tz4678 ★★
() автор топика
Ответ на: комментарий от tz4678

они, мягко говоря, не равнозначные. Но если тебя устраивает - вперёд

Ford_Focus ★★★★★
()
Ответ на: комментарий от tz4678

парсинг аргументов - едва ли не половина кода в такой задаче

using System;
using System.Net;
using System.Threading.Tasks;

namespace development16453699
{
    class Program2
    {
        static void Main(string[] args)
        {
            Parallel.ForEach(
                args[1].Split("\n"),
                new ParallelOptions { MaxDegreeOfParallelism = 10 },
                url =>
                {
                    try
                    {	
                        HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(url);
                        HttpWebResponse wres = (HttpWebResponse)wreq.GetResponse();
                        Console.WriteLine($"Status Code of {url} is {(int)wres.StatusCode} {wres.StatusDescription}");
                        wres.Close();
                    }
                    catch(Exception e)
                    {
                        Console.WriteLine("\n\n\nThe following Exception was raised : {0}",e.Message);
                    }
                }
            );
        }
    }
}

много сэкономил? а стоило ли того?

Ford_Focus ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.