У меня длинный список IP-адресов, которые не в порядке. Мне нужно выяснить, сколько IP-адресов существует до / после определенного IP-адреса. Как мне этого добиться?
У меня длинный список IP-адресов, которые не в порядке. Мне нужно выяснить, сколько IP-адресов существует до / после определенного IP-адреса. Как мне этого добиться?
Ответы:
Может быть, самый простой,
sed -n '/pattern/{=; q;}' file
Спасибо @JoshepR за указание на ошибку
dc
.
Я сделал это двумя способами, хотя я думаю, что мне это нравится больше всего:
: $(( 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
По номеру строки:
"$IP"
затем \n
ewlinetr
- который переводит нули в \n
Ewlines, а затем в~/file
Вот немного кода 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"
$.
вместо счетчика?
$after
для $. - $before
.
$. - 1
, сохраните $.
в $tmp
. Конец печати $. - $tmp
. Поэтому нам не нужен счетчик как до, так и после. Конечно, это менее читабельно, чем у вас.
Я пробовал следующие команды, которые немного сложны, но дали бы точные результаты:
После:
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
Grep
имеет функцию, которая может подсчитать, сколько раз найден определенный шаблон. Если вы используете -c
команду, которая сделает это. С помощью команды -c
and -v
это будет подсчитывать, сколько раз это не соответствует конкретному шаблону
Пример:
grep -c -v <pattern> file
Так что если вы попробуете что-то вроде:
grep -c -v 192.168.x.x file.log
это должно работать.