Підрахуйте загальну кількість рядків до / після відповідності шаблону


9

У мене довгий список IP-адрес, які не є послідовними. Мені потрібно знайти, скільки IP-адрес є до / після певної IP-адреси. Як я можу цього досягти?


Ви дублювали IP?
cuonglm

Ні. Усі IP-адреси унікальні.
Mandar Shinde

Що означає до / після значення для IP-адреси? Зокрема, у вас є і IPv4, і IPv6 адреси? Як вони порівнюються?
vinc17

Вам потрібен файл відсортований?
cuonglm

2
@ vinc17 - файл містить лише IP-адреси (IPv4), інші дані не включаються. Якщо загалом 1000 IP-адрес, а збіг знайдено на 300-му місці, значить, перед матчем є 299 рядків і 700 рядків після матчу.
Mandar Shinde

Відповіді:


8

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

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

Але це не має нічого спільного з IP-адресами зокрема.


4

Можливо, найпростіше,

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

Дякуємо @JoshepR за вказівку на помилку


Це просто виводить номер рядка, на якому виникла викрійка.
Джозеф Р.

@JosephR. - немає, він друкує кожен номер рядка , на якій кожен має місце збіг.
mikeserv

@mikeserv Я знаю, але OP вказав, що 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переводить втручаються \newlines до, і 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"потім електронну \nлінію
  4. виводить труби до tr- що переводить нулі в \newlines потім у~/file

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.
Mandar Shinde

2
@ Джозеф Р .: Чому ви не використовуєте $.замість лічильника?
cuonglm

@Gnouc Я, звичайно, міг. Я просто думаю , що це більш читабельним , ніж установка $afterдля $. - $before.
Джозеф Р.

Ні, я маю на увазі: якщо відповідати, друкувати $. - 1, зберігати $.в $tmp. Кінцевий друк $. - $tmp. Тому нам не потрібен лічильник як до, так і після. Звичайно, це менш читається, ніж ваше.
cuonglm

@MandarShinde Перегляньте редагування. Я додав чисту відповідь Баша.
Джозеф Р.

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

1

Grepмає функцію, яка може підраховувати кількість разів знайденого певного шаблону. Якщо ви використовуєте -cкоманду, яка це зробить. З -cі -vкомандами, це буде підрахувати , скільки разів це не відповідає певним шаблоном

Приклад:

grep -c -v <pattern> file

Тож якщо ви спробуєте щось на кшталт:

grep -c -v 192.168.x.x file.log це повинно працювати.


При цьому підраховується кількість подій цільової IP. Це не те, про що просила ОП.
Джозеф Р.

Я щойно відредагував його, якщо він просить порахувати всі інші IP-адреси до і після певного IP-адреси, редагування має працювати для нього.
ryekayo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.