ฉันมีรายการที่อยู่ IP จำนวนมากซึ่งไม่ได้เรียงตามลำดับ ฉันต้องการค้นหาจำนวนที่อยู่ IP ที่มีอยู่ก่อน / หลังที่อยู่ IP ที่เฉพาะเจาะจง ฉันจะบรรลุสิ่งนี้ได้อย่างไร
ฉันมีรายการที่อยู่ IP จำนวนมากซึ่งไม่ได้เรียงตามลำดับ ฉันต้องการค้นหาจำนวนที่อยู่ IP ที่มีอยู่ก่อน / หลังที่อยู่ IP ที่เฉพาะเจาะจง ฉันจะบรรลุสิ่งนี้ได้อย่างไร
คำตอบ:
จำนวนบรรทัดก่อนและหลังการแข่งขันรวมถึงการจับคู่ (เช่นคุณต้องลบ 1 จากผลลัพธ์หากคุณต้องการยกเว้นการแข่งขัน):
sed -n '0,/pattern/p' file | wc -l
sed -n '/pattern/,$p' file | wc -l
แต่สิ่งนี้ไม่เกี่ยวข้องกับที่อยู่ 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 for loop หลังจากนั้นสำหรับ output มันนับเส้นรวมในไฟล์ที่มีและได้รับหมายเลขบรรทัดแรกที่จับคู่กับ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
ewlines ที่แทรกเข้าไปและread
อ่านครั้งแรกของsed
ผลการค้นหา 's เข้า$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
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
End $. - $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
awk
วิธีการแก้ปัญหาการรายงานจำนวนเส้นก่อนและหลังการแข่งขันที่ผ่านมา
awk '/192\.168\.1\.1/{x=NR};{y=NR} END{printf "before-%d, after-%d\n" , x-1, y-x}' file
Grep
มีคุณสมบัติที่สามารถนับจำนวนครั้งที่พบรูปแบบเฉพาะ หากคุณใช้-c
คำสั่งที่จะทำเช่นนั้น ด้วยการ-c
และ-v
คำสั่งนี้จะนับจำนวนครั้งนี้ไม่ตรงกับรูปแบบเฉพาะ
ตัวอย่าง:
grep -c -v <pattern> file
ดังนั้นหากคุณลองทำสิ่งที่ชอบ:
grep -c -v 192.168.x.x file.log
ที่ควรได้ผล