Подсчитать общее количество строк до / после сопоставления с образцом

9

У меня длинный список IP-адресов, которые не в порядке. Мне нужно выяснить, сколько IP-адресов существует до / после определенного IP-адреса. Как мне этого добиться?

Мандар Шинде
источник
У вас есть дублированный IP?
cuonglm
Нет. Все IP-адреса являются уникальными.
Мандар Шинде
Что означает до / после для IP-адреса? В частности, есть ли у вас адреса IPv4 и IPv6? Как они сравниваются?
vinc17
Вам нужен файл отсортирован?
cuonglm
2
@ vinc17 - Файл содержит только IP-адреса (IPv4), другие данные не включены. Если в общей сложности 1000 IP-адресов и совпадение найдено в 300-м месте, это означает, что до совпадения осталось 299 строк, а после совпадения - 700 строк.
Мандар Шинде

Ответы:

8

Количество строк до и после матча, включая совпадение (т.е. вам нужно вычесть 1 из результата, если вы хотите исключить совпадение):

sed -n '0,/pattern/p' file | wc -l
sed -n '/pattern/,$p' file | wc -l

Но это не имеет ничего общего с IP-адресами, в частности.

vinc17
источник
4

Может быть, самый простой,

sed -n '/pattern/{=; q;}' file

Спасибо @JoshepR за указание на ошибку

jpmuc
источник
Это просто печатает номер строки, на которой произошел шаблон.
Джозеф Р.
@JosephR. - нет, он печатает каждый номер строки, на которой происходит каждое совпадение.
mikeserv
@mikeserv Я знаю, но ОП указал, что IP-адреса являются уникальными. ОП также не хочет номер строки, где произошло совпадение (я); они хотят количество строк до появления шаблона и количество строк после него.
Джозеф Р.
@JosephR - самый быстрый способ прийти к этим подсчетам - это подсчитать номера строк - я бы, наверное, просто передал это напрямую dc.
mikeserv
@mikeserv Я не утверждаю, что информация из этого ответа бесполезна, я просто говорю, что этот код сам по себе не делает то, что хочет ОП.
Джозеф Р.
3

Я сделал это двумя способами, хотя я думаю, что мне это нравится больше всего:

: $(( afterl=( lastl=$(wc -l <~/file) ) - 2 -
  $(( beforel=( matchl=$(sed -n "/$IP/{=;q;}" <~/file) ) - 1
)) ))
for n in last match afters befores
do  printf '%s line%s :\t%d\n' \
        "${n%s}" "${n##*[!s]}" $((${n%s}l))
done

Это сохраняет все эти переменные как текущие переменные оболочки и затем оценивает их в цикле for для вывода. Он подсчитывает общее количество строк в файле wcи получает номер первой совпавшей строки с sed.

Его вывод:

last line :     1000
match line :    200
after lines :   799
before lines :  199

Я также сделал:

sed -n "/$IP/=;\$=" ~/file |  
tr \\n \  | { 
IFS=' ' read ml ll 
printf '%s line%s:\t%d\n' \
    last '' $((ll=${ll##* }))
    match '' $ml \
    after s "$((al=ll-ml-1)) \ 
    before s $((bl=ml-1))
}

sedпечатает только совпадающие и последние номера строк, а затем trпереводит промежуточные \nстроки ви readчитает первые sedрезультаты в $mlи все остальные в $ll. Возможные множественные совпадения обрабатываются путем удаления всех значений, кроме последнего, из $llрасширения при повторной установке позже.

Его вывод:

last line :     1000
match line :    200
after lines :   799
before lines :  199

Оба метода были проверены на файл, сгенерированный следующим образом:

IP='some string for which I seek' 
for count in 1 2 3 4 5 
do  printf '%.199d%s\n' 0 "$IP" 
done | tr 0 \\n >~/file 

По номеру строки:

  1. устанавливает строку поиска
  2. зацикливается пять раз, чтобы обеспечить несколько совпадений
  3. печатает 199 нулей, а "$IP"затем \newline
  4. трубы выводятся на tr- который переводит нули в \nEwlines, а затем в~/file
mikeserv
источник
2

Вот немного кода Perl, который делает это:

perl -ne '
     if(1 .. /192\.168\.1\.1/) { $before++ }
     else                      { $after++  }
     $before--; # The matching line was counted
     END{print "Before: $before, After: $after\n"}' your_file

Это подсчитывает общее количество строк до и после строки, содержащей IP 192.168.1.1. Замените на нужный вам IP.

Используя только Bash:

before=0
match=0
after=0
while read line;do
    if [ "$line" = 192.168.1.1 ];then
        match=1
    elif [ $match -eq 0 ];then
        before=$(($before+1))
    else
        after=$(($after + 1))
    fi
done < your_file
printf "Before: %d, After: %d\n" "$before" "$after"
Джозеф Р.
источник
BASH является предпочтительным.
Мандар Шинде
2
@ Джозеф Р .: Почему бы вам не использовать $.вместо счетчика?
cuonglm
@Gnouc Я мог бы, конечно. Я просто думаю , что это более читаемым , чем установка $afterдля $. - $before.
Джозеф Р.
Нет, я имею в виду: если соответствует, распечатайте $. - 1, сохраните $.в $tmp. Конец печати $. - $tmp. Поэтому нам не нужен счетчик как до, так и после. Конечно, это менее читабельно, чем у вас.
cuonglm
@MandarShinde Пожалуйста, смотрите редактирование. Я добавил чистый ответ Bash.
Джозеф Р.
2

Я пробовал следующие команды, которые немного сложны, но дали бы точные результаты:

После:

a=$(cat file | wc -l) && b=$(cat -n file | grep <Pattern> | awk '{print $1}') && echo "$a - $b" | bc -l

Перед:

echo "`cat -n file | grep <Pattern> | awk '{print $1}'`-1" | bc -l
Мандар Шинде
источник
2

awkРешение количества строк отчетов до и после последнего матча

awk '/192\.168\.1\.1/{x=NR};{y=NR} END{printf "before-%d, after-%d\n" , x-1, y-x}'  file
Iruvar
источник
1

Grepимеет функцию, которая может подсчитать, сколько раз найден определенный шаблон. Если вы используете -cкоманду, которая сделает это. С помощью команды -cand -vэто будет подсчитывать, сколько раз это не соответствует конкретному шаблону

Пример:

grep -c -v <pattern> file

Так что если вы попробуете что-то вроде:

grep -c -v 192.168.x.x file.log это должно работать.

ryekayo
источник
Это подсчитывает количество вхождений целевого IP. Это не то, что попросил ОП.
Джозеф Р.
Я только что отредактировал его, если он просит подсчитать все другие IP-адреса до и после определенного IP-адреса, редактирование должно работать для него.
ryekayo