Замените итерацию массива регулярным выражением

Я хочу найти частично совпадающие префиксы ipv6 в двух массивах. Например, 2001:db8: из одного массива будет соответствовать 2001:db8:1::/48 и 2001:db8:2::/48 из другого.

У меня уже это работает, повторяя один массив другим:

ru_routes=( $(curl -4 ftp://ftp.ripe.net/ripe/stats/delegated-ripencc-latest | egrep -o '\|RU\|ipv6\|.+?::\|[0-9]+' | cut -d'|' -f4 | sed 's/::$/:/g') );
msk_ix_routes=( $(curl -4 http://www.msk-ix.ru/download/lg/msk_ipv6_pfx.txt.gz | gunzip | egrep -o '\b.*::/[0-9]*') );
routes=();
for item1 in ${msk_ix_routes[@]}; do
    for item2 in ${ru_routes[@]}; do
        if [[ $item1 = $item2* ]]; then
            routes+=( $item1 );
            break
        fi
    done
done

Но на моем маршрутизаторе mips он работает довольно медленно (~ 90 секунд). Я нашел этот полезный ответ, который работает намного быстрее, но я не могу заставить его работать так же, как и выше. И я не думаю, что мне нужна конструкция «если», как в примере, потому что она сделает одно и то же дважды. Моя нерабочая версия:

msk=" ${msk_ix_routes[*]} ";         # add framing blanks

for item in ${ru_routes[@]}; do
  routes+=( egrep -o "$item[\S]*/g" <<< $msk );
done

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

Кстати, я использовал "comm" в первой версии, которая работает еще быстрее, но затем она делает только точное совпадение, поэтому я начал играть с циклами:

routes=( $(comm -12 <(printf '%s\n' "${ru_routes[@]}" | LC_ALL=C sort) <(printf '%s\n' "${msk_ix_routes[@]}" | LC_ALL=C sort)) );

person Xand    schedule 31.08.2014    source источник
comment
Независимо от чего-либо еще, вы хотите процитировать расширения списка [@], чтобы предотвратить разделение слов элементов массива (вероятно, это не проблема в вашем случае, но правильный способ делать что-то в целом).   -  person Etan Reisner    schedule 01.09.2014
comment
А как насчет тех двух нерабочих вариантов, которые не работают? Что они делают? (Второй похоже, что он будет создавать пустой список, поскольку тест [[ не возвращает никакого содержимого (только код возврата). Вы почти наверняка хотите, чтобы этот тест находился в блоке if, а затем добавлял $item к списку (например, в связанном вопросе).   -  person Etan Reisner    schedule 01.09.2014
comment
Я согласен со вторым вариантом (убрал его). Первый дает мне 889111 совпадений вместо 4xx действительных совпадений. $item будет точным совпадением, и я хочу получить все более длинные совпадения (подстрока)   -  person Xand    schedule 01.09.2014


Ответы (1)


Скрипты Bash совсем не хороши по эффективности. Попробуй это:

#!/bin/bash

# e. g.: ripencc|RU|ipv6|2001:640::|32|19991115|allocated -> ^2001:640:
awk -v FS='|' \
    '$2 == "RU" && $3 == "ipv6" { sub(/::/, ":", $4); print "^" $4 }' \
    <(curl -4 ftp://ftp.ripe.net/ripe/stats/delegated-ripencc-latest) \
|\
# grep e. g. '^2001:640:' in '2001:640:8000::/33'
grep --basic-regexp --file - \
    <(curl -4 http://www.msk-ix.ru/download/lg/msk_ipv6_pfx.txt.gz | gunzip)
person Dmitry Alexandrov    schedule 01.09.2014
comment
Спасибо, товарищ Дмитрий, ваша последняя правка удалась. И это намного быстрее, чем циклы. Каким-либо образом удалить повторяющиеся записи из msk_ipv6_pfx.txt? Например, 2a02:bc8::/32 и 2a02:bc8:fffe::/48. Оба маршрута будут идти на IX, но достаточно более высокого префикса (делегирован 2a02:bc8::/32). Еще раз спасибо - person Xand; 01.09.2014
comment
@Xand Не за что. :-) Что касается удаления дублирующихся записей в msk_ipv6_pfx.txt, это выглядит достаточно нетривиально, чтобы это был отдельный вопрос, собственно здесь, на SO. Но да, конечно, это возможно. Например: $ tac msk_ipv6_pfx.txt | awk -F '::' -v P='^$' '!/^[# ]/ && $0 != "" && $1 !~ P { P = "^" $1; print }'. Однако это не оптимальный способ — его можно выполнить без реверсирования файла. Вам нужны комментарии? - person Dmitry Alexandrov; 01.09.2014
comment
Я вижу, что количество строк уменьшилось, но оба префикса, упомянутые выше, остались (в любом случае нужно будет переночевать). Но я был бы очень признателен за подсказки о перенаправлениях для подачи grep с файлом msk-ix после curl и gunzip. В противном случае, я думаю, нужно определить его как отдельную переменную. Спасибо - person Xand; 01.09.2014
comment
@Xand Что касается curl, если временные файлы не подходят - см. отредактированный ответ. - person Dmitry Alexandrov; 01.09.2014
comment
@Xand Что касается удаления избыточности msk_ipv6_pfx.txt, ну, я был невнимателен — на самом деле tac недостаточно, мы пересортировали файл: $ sort -n msk_ipv6_pfx.txt | awk -F '::' -v P='^$' '!/^[# ]/ && $0 != "" && $1 !~ P { P = "^" $1; print }'. - person Dmitry Alexandrov; 01.09.2014
comment
Это выглядело бы чище с временными файлами, но тогда это увеличит износ флэш-памяти на маршрутизаторе. У него есть busybox со встроенным grep, поэтому пришлось удалить --basic-regexp. Работает нормально. Итак, в конце концов я получил однострочник, который делает работу за 17 секунд. Дмитрий, вы показали мне кое-что новое и реально сэкономили неделю гугления. Большое спасибо) - person Xand; 01.09.2014
comment
Я проверил вывод более точно и заметил, что часть awk не работает должным образом, несмотря на выбранную мной сортировку. 2001:14e8:1::/48 2001:14e8:2::/48 2001:14e8::/32 2001:14e8::/48 Expected result is 2001:14e8::/32, но остается только 2001:14e8::/48. Какие-нибудь рекомендации? Я действительно не понимаю часть !/^[# ]/. Спасибо - person Xand; 24.10.2014