![Bash:根据 y 列中的值计算 x 列中值的出现次数](https://linux22.com/image/92310/Bash%EF%BC%9A%E6%A0%B9%E6%8D%AE%20y%20%E5%88%97%E4%B8%AD%E7%9A%84%E5%80%BC%E8%AE%A1%E7%AE%97%20x%20%E5%88%97%E4%B8%AD%E5%80%BC%E7%9A%84%E5%87%BA%E7%8E%B0%E6%AC%A1%E6%95%B0.png)
我有一个像这样的字符串。
data = "state:: 4 caller_contact:: sip:[email protected]:5080;transport=udp
state:: 4 caller_contact:: sip:[email protected]:5080;transport=udp
state:: 4 caller_contact:: sip:[email protected]:5080;transport=udp
state:: 4 caller_contact:: sip:[email protected]:5080;transport=udp
state:: 2 caller_contact:: sip:[email protected]:5080;transport=udp
state:: 2 caller_contact:: sip:[email protected]:5080;transport=udp
state:: 1 caller_contact:: sip:[email protected]:5080;transport=udp"
我需要编写一个 bash 脚本来计算每个 IP 例如 192.168.26 具有状态 4 或状态 2 的次数。(该字符串不包含“/n”)
我无法解析该字符串并根据每个 IP 计算值。
答案1
我不确定这是否适用于您可能拥有的每种可能的组合,但它适用于您提供的小样本:
sed "1,\$s/state/\nstate/g" file | grep state > NewFile
for IPADDR in $(cat NewFile | cut -d"@" -f2|cut -d":" -f1|sort -n|uniq);do
for STATE in 2 4 ;do
LineCount=$(grep "${IPADDR}" NewFile |grep "state:: ${STATE}"| wc -l)
echo "For IP address ${IPADDR}, status:: ${STATE} lines count is ${LineCount}"
done
done | grep -v "is 0"$
您可以在 for 循环中添加任意多个不同的 STATE 数字
基本上,您在每次出现字符串之前插入一个新行字符,state
从而形成大数据块,并将其分成多行。
答案2
查找唯一的 IP 并计算每个状态 4 或 2
for addr in $(grep -o '@[^:]\+' file | sort -u); do
echo -n ${addr#@}:\
grep -c ":: [24].*${addr#@}" file
done
或者使用 awk 执行任务
awk -F '[: @;=]+' '
$2 ~ /^[24]$/{
count[$6]++
}
END {
for(i in count)
print(i, count[i])
}
' file
答案3
这是我的小怪物。
#!/bin/bash
# monsterr.sh
if [ -z "$1" ] ; then
printf "%s\n" "Syntax error."
exit 2
fi
data="$1"
tmp=tmp$$
mkdir $tmp
parse() {
state=
ip=
i=0
while read l; do
((i++))
if [ $(($i%2)) -eq 0 ]; then
if [ $(($i%4)) -eq 2 ]; then
state=$l
else
IFS=: read x ip x < <(printf %s $l)
IFS=@ read x ip < <(printf %s $ip)
printf "%s\n" $state >> "$tmp/$ip"
fi
fi
done < <(printf "%s\n" $data)
}
report() {
cd $tmp
for f in * ; do
declare -a count
printf "IP: %s\n" $f
while read s ; do
((count[$s]++))
done < $f
for s in ${!count[@]}; do
printf "State: %s, count: %s\n" $s ${count[$s]}
done
printf '\n'
unset count
done
cd - 2 > /dev/null
}
parse
report
rm -r $tmp
用法:
$ data="state:: 4 caller_contact:: sip:[email protected]:5080;transport=udp state:: 4 caller_contact:: sip:[email protected]:5080;transport=udp state:: 4 caller_contact:: sip:[email protected]:5080;transport=udp state:: 4 caller_contact:: sip:[email protected]:5080;transport=udp state:: 2 caller_contact:: sip:[email protected]:5080;transport=udp state:: 2 caller_contact:: sip:[email protected]:5080;transport=udp state:: 1 caller_contact:: sip:[email protected]:5080;transport=udp"
$ ./monsterr.sh "$data"
IP: 192.168.10.01
State: 4, count: 1
IP: 192.168.10.03
State: 4, count: 1
IP: 192.168.10.07
State: 1, count: 1
IP: 192.168.10.11
State: 2, count: 1
State: 4, count: 1
IP: 192.168.10.26
State: 2, count: 1
State: 4, count: 1
答案4
grep
您想要处理的行,可以使用sed
.sed
使用 、排序和计数从行中获取 2 个子字符串:
sed -n '/state:: [24] .*@/ s/.*:: \([24]\)[^@]*@\([^:]*\).*/State \1 IP \2/p' file |
sort | uniq -c | sort -n