เก็บ 50 บรรทัดสุดท้ายใน logfile อย่างไร


21

ฉันพยายามเก็บ 50 บรรทัดสุดท้ายในไฟล์ของฉันที่ฉันบันทึกอุณหภูมิทุกนาที ฉันใช้คำสั่งนี้:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test

แต่ผลลัพธ์คือไฟล์ทดสอบที่ว่างเปล่า ฉันคิดว่ามันจะแสดงไฟล์ทดสอบ 50 บรรทัดสุดท้ายและใส่ลงในไฟล์ทดสอบ เมื่อฉันใช้คำสั่งนี้:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test2

มันทำงานได้ดี มี 50 บรรทัดในไฟล์ test2

ใครช่วยอธิบายฉันได้ว่ามีปัญหาอยู่ที่ไหน


2
บางอย่างเช่น rrdtool อาจเหมาะสมกว่าสำหรับการเก็บบันทึก N (ท่ามกลางสถิติอื่น ๆ ) เมื่อเวลาผ่านไป
thrig

ดูเพิ่มเติมที่unix.stackexchange.com/a/147620/117549
Jeff Schaller

2
ปัญหาการตัดทอนแบบคลาสสิก
haylem

หากคุณใช้ไพ ธ อนเพื่อสร้างบันทึกของคุณคุณควรดูในloggingโมดูล
Wayne Werner

คำตอบ:


29

ปัญหาคือเปลือกของคุณตั้งค่าไปป์ไลน์คำสั่งก่อนเรียกใช้คำสั่ง ไม่ใช่เรื่องของ "อินพุทและเอาท์พุท" มันเป็นเนื้อหาของไฟล์ที่ได้หายไปแล้วก่อนที่หางจะวิ่ง มันไปบางอย่างเช่น:

  1. เชลล์เปิด>ไฟล์เอาต์พุตสำหรับการเขียนโดยตัดทอน
  2. เชลล์ตั้งค่าให้ใช้ file-descriptor 1 (สำหรับ stdout) สำหรับเอาต์พุตนั้น
  3. tailรันเปลือก
  4. tailวิ่งเปิด/home/pi/Documents/testและไม่พบสิ่งใดในนั้น

มีวิธีแก้ไขปัญหาต่าง ๆ แต่ที่สำคัญคือการเข้าใจปัญหาสิ่งที่เกิดขึ้นจริงและทำไม

สิ่งนี้จะสร้างสิ่งที่คุณกำลังมองหา

echo "$(tail -n 50 /home/pi/Documents/test)" > /home/pi/Documents/test

คำอธิบาย:

  • $() เรียกว่าการทดแทนคำสั่งซึ่งดำเนินการ tail -n 50 /home/pi/Documents/test
  • เครื่องหมายคำพูดรักษาเส้นแบ่งในเอาท์พุท
  • > /home/pi/Documents/testเปลี่ยนเส้นทางการส่งออกของecho "$(tail -n 50 /home/pi/Documents/test)"ไปยังไฟล์เดียวกัน

ขอบคุณมันใช้งานได้ดี! ฉันมีอีกหนึ่งคำถาม คุณช่วยอธิบายขั้นตอนการทำงานของคุณทีละขั้นตอนได้ไหม
dorinand

1
แต่ทำไมในกรณีของคุณทุบตีไม่ทำงาน> ก่อน ฉันไม่เข้าใจวิธีทุบตีถึงคำสั่ง มีใครอธิบายได้บ้าง
dorinand

1
> อยู่บนคำสั่ง echo ดังนั้นจะถูกดำเนินการเมื่อคำสั่ง echo เริ่มต้นการดำเนินการ ไม่สามารถเริ่มการทำงานก่อนที่จะถูกเขียน การทดแทนตัวแปรคือสิ่งที่เขียนคำสั่ง มันรันคำสั่งที่ซ้อนกันและสร้างคำสั่ง echo โดยการแทนค่า
jobermark

เมื่อฉันพยายามใช้สิ่งเดียวกันสำหรับไฟล์บันทึก 44GB โดยใช้ 5000 บรรทัดแทนที่จะเป็น 50 ฉันได้รับข้อผิดพลาดbash: xrealloc: cannot allocate 18446744071562067968 bytes
Carmageddon

8

อีกวิธีในการเปลี่ยนเส้นทางการล้างไฟล์ก่อนอื่นคือใช้spongeจากmoreutilspackge ดังนี้:

tail -n 50 /home/pi/Documents/test | sponge /home/pi/Documents/test

6

นี่เป็นเพราะ bash ประมวลผลการเปลี่ยนเส้นทางด้วยอัน>แรกลบเนื้อหาของไฟล์ จากนั้นมันรันคำสั่ง หากคุณใช้งาน>>50 บรรทัดสุดท้ายจะต่อท้ายสิ่งที่อยู่ในไฟล์ ในกรณีนี้คุณจะต้องซ้ำ 50 บรรทัดซ้ำสองครั้ง

คำสั่งทำงานได้ตามที่คาดไว้เมื่อเปลี่ยนเส้นทางไปยังไฟล์อื่น นี่เป็นวิธีหนึ่งในการเขียน 50 บรรทัดสุดท้ายของไฟล์ไปยังไฟล์ที่มีชื่อเดียวกัน:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 && mv /home/pi/Documents/test2 /home/pi/Documents/test

นี่เป็นครั้งแรกที่เขียน 50 บรรทัดสุดท้ายไปยังไฟล์ชั่วคราวซึ่งจะถูกย้ายโดยใช้mvเพื่อแทนที่ไฟล์ต้นฉบับ

ตามที่ระบุไว้ในความคิดเห็นสิ่งนี้จะไม่ทำงานหากไฟล์ยังคงเปิดอยู่ การย้ายไฟล์ยังสร้าง inode ใหม่และอาจเปลี่ยนความเป็นเจ้าของและสิทธิ์ วิธีที่ดีกว่าในการทำเช่นนี้โดยใช้ไฟล์ชั่วคราวคือ:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 ; cat /home/pi/Documents/test2 > /home/pi/Documents/test

ไฟล์ชั่วคราวสามารถลบได้แม้ว่าทุกครั้งที่เกิดเนื้อหาจะถูกเขียนทับ


ขอขอบคุณ. คุณช่วยอธิบายทีละขั้นตอนว่าฉันทุบตีรันได้อย่างไร? ฉันไม่สามารถจินตนาการได้ว่ามันทำงานอย่างไร
dorinand

tail -50 /home/pi/Documents/test >/tmp/foo && cat /tmp/foo >/home/pi/Documents/test
สตีฟ

1
โปรดทราบว่าสิ่งนี้จะไม่ทำงานหากไฟล์บันทึกการทำงานยังคงเปิดอยู่โดยกระบวนการบันทึก (ซึ่งจะทำการบันทึกต่อไปยังไฟล์ต้นฉบับที่ถูกลบไป) tempfile + ย้ายผลลัพธ์ใน inode ใหม่ (ทำลายฮาร์ดลิงก์ใด ๆ ) และอาจเป็นเจ้าของหรือ perms ที่แตกต่างกัน tail ... > temp ; cat temp > orig ; rm -f tempโรงงาน
cas

4

เนื่องจากคุณเห็นปัญหาหลักของการเปลี่ยนเส้นทางของเชลล์นี่เป็นอีกทางเลือกหนึ่งในการตัดไฟล์เป็น 50 บรรทัดสุดท้าย:

file=/path/to/the/file
n=$(( $(wc -l < "$file") - 50 ))
[[ $n -gt 0 ]] && sed -i 1,${n}d "$file"

การทำงานอย่างหนักกระทำโดย (GNU) -iที่มีคุณสมบัติ "การแก้ไขในสถานที่" ซึ่งทำงานภายใต้ฝาครอบโดยการสร้างเอาต์พุตในไฟล์ชั่วคราว บรรทัดที่เหลือตั้งค่าคณิตศาสตร์สำหรับการทำงานของ sed คือ:

  1. นับบรรทัดในไฟล์ (wc ) จากนั้นลบ 50; nกำหนดว่า
  2. หากn เป็นค่าบวกให้รันคำสั่ง sed เพื่อลบบรรทัด 1 ถึง n

4
printf '%s\n' '1,$-50d'   w | ed -s /home/pi/Documents/tes

printfจะใช้ในการคำสั่งท่อ (ต่อหนึ่งบรรทัด) edลง edคำสั่งคือ:

  • 1,$-50d - ลบทั้งหมดยกเว้น 50 บรรทัดสุดท้าย
  • w - เขียนไฟล์ที่แก้ไขแล้วกลับไปที่ดิสก์

ไม่มีการเปลี่ยนเส้นทางที่เกี่ยวข้องดังนั้นเชลล์ไม่สามารถเขียนทับไฟล์เอาต์พุตก่อนที่จะถูกอ่าน

นอกจากนี้ยังแตกต่างจากการแก้ไขแบบ "in-place" ส่วนใหญ่ (ซึ่งโดยทั่วไปจะจำลองการแก้ไขแบบ "in-place" เท่านั้นโดยการสร้างไฟล์ temp แล้วเปลี่ยนชื่อเป็นแบบเดิม) ทำการedแก้ไขไฟล์ต้นฉบับ - ดังนั้นจึงคง inode เดียวกัน ( และเจ้าของกลุ่มและสิทธิ์ - tempfile + mv จะเปลี่ยน inode เสมอและอาจเปลี่ยนค่าอื่น ๆ ตามสถานการณ์)


4

ในแทร็กที่แตกต่างกันเล็กน้อยคุณสามารถใช้logrotate(8)เพื่อสำรองไฟล์บันทึกเป็นประจำเพื่อเพิ่มชื่อไฟล์และลบไฟล์เก่า

นี่คือวิธีจัดการล็อกไฟล์ของระบบหลักเพื่อป้องกันไม่ให้ไฟล์ยาวเกินไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.