จะทำ 'wc -l' อย่างต่อเนื่องกับ gnu texttools ได้อย่างไร?


28

ฉันรู้แน่นอนว่า

cat logfile.txt | wc -l
120

จะบอกจำนวนบรรทัดในไฟล์ให้ฉัน

แต่ทว่า

tail -f logfile.txt

จะแสดงบรรทัดใหม่ที่โปรแกรมอื่นเขียนถึงlogfile.txtฉัน

เป็นไปได้หรือไม่ที่จะรวมทั้งสองอย่างเพื่อให้ฉันได้รับการนับจำนวนบรรทัดใหม่อย่างต่อเนื่องของ logfile.txt ด้วยยูทิลิตี้ข้อความมาตรฐาน?

ฉันรู้เกี่ยวกับ

watch wc -l logfile.txt

แต่ฉันไม่ต้องการนับไฟล์ใหม่ทุกครั้งที่ดูเหมือนว่าจะเป็นการสิ้นเปลือง หนึ่งจะต้องมีการผนวกเพียงนับทุกวินาทีหรือมากกว่านั้นและอาจจะ\rแทนที่จะเป็น\nในตอนท้ายของบรรทัด


1
ไฟล์ของคุณมีขนาดใหญ่หรือไม่ที่เล่าทุกอย่างว่าเป็นปัญหาหรือไม่ ในแง่ของเสีย: การcatส่งออกท่อไปwcยังเป็นของเสียที่มีขนาดใหญ่ !!
Bernhard

ใช่มันอาจมีขนาดใหญ่มาก
towi

คำตอบ:


36

อาจจะ:

tail -n +1 -f file | awk '{printf "\r%lu", NR}'

ระวังว่ามันจะส่งออกตัวเลขสำหรับทุกบรรทัดของการป้อนข้อมูล (แม้ว่าจะแทนที่ค่าก่อนหน้านี้ถ้าส่งไปยังสถานี)

หรือคุณสามารถใช้งานtail -fด้วยมือในเชลล์:

n=0
while :; do 
  n=$(($n + $(wc -l)))
  printf '\r%s' "$n"
  sleep 1
done < file

(ทราบว่ามันจะทำงานได้ถึงหนึ่งwcและเป็นหนึ่งในsleepคำสั่งต่อวินาทีซึ่งไม่ได้หอยทั้งหมดได้สร้างขึ้นใน. ด้วยksh93ในขณะที่sleepมีการ builtin ที่จะได้รับการสร้างขึ้นในwc(อย่างน้อยใน Debian) คุณต้องเพิ่ม/opt/ast/binที่ด้านหน้าของ$PATH(ไม่ว่า ไดเรกทอรีนั้นมีอยู่หรือไม่) หรือใช้command /opt/ast/bin/wc(ไม่ต้องถาม ... ))

คุณสามารถใช้pvเช่นเดียวกับใน:

tail -n +1 -f file | pv -bl > /dev/null

แต่ระวังว่ามันจะเพิ่มk, M... ต่อท้ายเมื่อจำนวนมากกว่า 1000 (และมีไม่ดูเหมือนจะเป็นวิธีการที่รอบ )


tail | awkวิธีแก้ปัญหาของคุณ รู้จักตัวเลือกของคุณ: -n +0จะไม่เกิดขึ้นกับฉันในการรวมกันนี้
towi

2
Whoo! pv- เครื่องมือใหม่ที่มีประโยชน์อีกตัว ขอบคุณมัด
towi

ด้วย grep คุณสามารถเพิ่มตัวกรองในสตรีมของคุณ:tail -n +0 -f <my.log> | grep --line-buffered <mystring> | awk '{printf "\r%lu", NR}'
tombolinux

2
@tombolinux, เป็นซูเปอร์awk greptail -n +0 -f file | awk '/mystring/ {printf "\r%lu", ++n}'
Stéphane Chazelas

เย็น. ฉันเพิ่มEND{print ""}เพื่อให้awkพิมพ์บรรทัดใหม่ในตอนท้าย
pLumo

6

ลองนับด้วยความบริสุทธิ์bashโดยที่wc:

a=0 ; tail -f file | while read -r line ; do ((a++)) ; echo $a ; done

หรือแม้กระทั่งสิ่งนี้เพื่อเขียนค่าก่อนหน้า:

a=0 ; tail -f file | while read -r line ; do ((a++)) ; echo -ne "\r$a" ; done

1

ฉันไม่เชื่อว่ามีอะไรอย่างนั้น แต่มันควรจะง่ายที่จะทำอะไรบางอย่างตาม:

#!/usr/bin/perl

$for_a_while = 1;

$oldcount = -1;
$count = 0;
open($fh, "<", $ARGV[0]);

for (;;) {
  for ($curpos = tell($fh); <$fh>; $curpos = tell($fh)) {
    $count++;
  }
  if($count != $oldcount) {
    print "$count\n";
    $oldcount = $count;
  }
  sleep($for_a_while);
  seek($fh, $curpos, 0);
}

(ความคิดทั่วไปเปลจากperlfunc(1))


1
printf foo >> fileจำนวนจะเพิ่มขึ้นทุกครั้งที่คุณทำทุก คุณจะต้องนับตัวอักษรขึ้นบรรทัดใหม่ (เช่นwc -lไม่ในการแก้ปัญหาเปลือกผมแนะนำ) <$fh>ไม่ได้บันทึกกลับโดย ฉันไม่คิดว่าคุณจำเป็นต้องใช้tellหรือseekเลย
Stéphane Chazelas

<$fh>อ่านบรรทัดโดยค่าเริ่มต้นไม่ได้บันทึก Perl manpage ที่อ้างถึงบอกว่าจะทำเช่นนี้เพื่อประโยชน์ของสภาพแวดล้อมที่ไม่ร่วมมือ (อาจขึ้นอยู่กับระบบไฟล์ฉันเดาว่า NFS หรือระบบไฟล์ที่ติดตั้งบนเครือข่ายอื่นอาจต้องใช้การกระตุ้นเล็กน้อย)
vonbrand

ลองด้วยตัวคุณเองเมื่อถึงจุดสิ้นสุดไฟล์<$fh>จะส่งกลับระเบียนแม้ว่าอักขระบรรทัดใหม่จะไม่ถูกยกเลิก ดังนั้นหากperlนั่งที่ท้ายไฟล์และมีคนทำในภายหลังprintf foo >> fileจากนั้น<$fh>จะส่งคืนfoo(ไม่ใช่บรรทัดเนื่องจากอักขระบรรทัดใหม่ไม่ได้ถูกยกเลิกด้วย) และ$countจะเพิ่มขึ้นแม้ว่าจะไม่มีการเพิ่มบรรทัดพิเศษลงในไฟล์
Stéphane Chazelas

OP ควรจะตรวจสอบ logfiles เขียนบรรทัดในเวลาหรือไม่
vonbrand

ไม่ซึ่งเป็นสาเหตุที่โซลูชันของคุณอาจไม่ทำงาน ตัวอย่างเช่นหากแอปพลิเคชันเขียนไปยังไฟล์บัฟเฟอร์เอาต์พุตเมื่อใดก็ตามที่กำหนดบรรทัดสุดท้ายจะไม่ถูกยกเลิกดังนั้นจะถูกนับสองครั้ง
Stéphane Chazelas

0

ดำเนินการต่อตามโซลูชัน awk: คุณอาจไม่จำเป็นต้องเห็นตัวนับฟ้องสำหรับแต่ละบรรทัดในบันทึกของคุณ ในกรณีนี้คุณสามารถทำได้เช่นนี้ (ตัวเลขจะเปลี่ยนสำหรับแต่ละ 10 บรรทัด):

tail -n +0 logfile.txt | \
    awk 'a+=1{}a%10==0{printf "\r%lu", a}END{printf "\r%lu", a}'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.