Cách giữ 50 dòng cuối cùng trong logfile


21

Tôi cố gắng giữ 50 dòng cuối cùng trong tệp của mình, nơi tôi tiết kiệm nhiệt độ mỗi phút. Tôi đã sử dụng lệnh này:

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

Nhưng kết quả là tập tin thử nghiệm trống. Tôi nghĩ rằng, nó sẽ liệt kê 50 dòng tệp thử nghiệm cuối cùng và chèn nó vào tệp thử nghiệm. Khi tôi sử dụng lệnh này:

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

nó đang hoạt động tốt Có 50 dòng trong tệp test2.

Ai có thể giải thích cho tôi vấn đề ở đâu?


2
Một cái gì đó như rrdtool có thể phù hợp hơn để giữ N bản ghi (trong số các số liệu thống kê khác) theo thời gian.
thrig


2
vấn đề cắt ngắn cổ điển
haylem

Nếu bạn đang sử dụng python để tạo nhật ký của mình, bạn nên xem xét loggingmô-đun
Wayne Werner

Câu trả lời:


29

Vấn đề là shell của bạn đang thiết lập đường ống lệnh trước khi chạy các lệnh. Đây không phải là vấn đề "đầu vào và đầu ra", đó là nội dung của tệp đã bị mất trước khi đuôi chạy. Nó đi một cái gì đó như:

  1. Shell mở >tệp đầu ra để ghi, cắt bớt nó
  2. Shell thiết lập để có bộ mô tả tệp 1 (cho thiết bị xuất chuẩn) được sử dụng cho đầu ra đó
  3. Vỏ thực thi tail.
  4. tailchạy, mở /home/pi/Documents/testvà không tìm thấy gì ở đó

Có nhiều giải pháp khác nhau, nhưng mấu chốt là hiểu vấn đề, điều gì thực sự sai và tại sao.

Điều này sẽ tạo ra những gì bạn đang tìm kiếm,

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

Giải trình :

  • $() được gọi là thay thế lệnh mà thực thi tail -n 50 /home/pi/Documents/test
  • các dấu ngoặc kép bảo toàn ngắt dòng trong đầu ra.
  • > /home/pi/Documents/testchuyển hướng đầu ra của echo "$(tail -n 50 /home/pi/Documents/test)"cùng một tệp.

Cảm ơn bạn nó hoạt động tốt! Tôi có một câu hỏi nữa. Bạn có thể vui lòng giải thích làm thế nào thủ tục của bạn làm việc từng bước?
dorinand

1
Nhưng tại sao trong trường hợp của bạn bash không thực hiện> đầu tiên? Tôi không hiểu làm thế nào bash xử lý lệnh. Ai có thể giải thích?
dorinand

1
> Là trên lệnh echo, vì vậy nó được thực thi khi lệnh echo bắt đầu thực thi. Nó không thể bắt đầu thực hiện trước khi nó được viết. Sự thay thế biến là những gì viết lệnh. Nó chạy lệnh lồng nhau và tạo lệnh echo bằng cách thay thế trong giá trị.
jobermark

Khi tôi cố gắng sử dụng tương tự cho tệp nhật ký 44gb bằng 5000 dòng thay vì 50, tôi gặp lỗibash: xrealloc: cannot allocate 18446744071562067968 bytes
Carmageddon

8

Một giải pháp khác cho việc chuyển hướng tệp xóa tệp trước tiên là sử dụng spongetừ gói moreutilsnhư vậy:

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

6

Điều này là do bash xử lý chuyển hướng với >lần đầu tiên, xóa nội dung của tệp. Sau đó, nó thực hiện lệnh. Nếu bạn sử dụng >>, 50 dòng cuối cùng sẽ được thêm vào cuối của những gì hiện có trong tệp. Trong trường hợp này, bạn có cùng 50 dòng được lặp lại hai lần.

Lệnh hoạt động như mong đợi khi chuyển hướng đến một tệp khác. Đây là một cách để viết 50 dòng cuối cùng của tệp vào một tệp có cùng tên:

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

Điều này đầu tiên ghi 50 dòng cuối cùng vào một tệp tạm thời, sau đó được di chuyển bằng cách sử dụng mvđể thay thế tệp gốc.

Như đã lưu ý trong các bình luận, điều này sẽ không hoạt động nếu tệp vẫn mở. Di chuyển tệp cũng tạo ra một nút mới và có thể thay đổi quyền sở hữu và quyền. Một cách tốt hơn để làm điều này bằng cách sử dụng một tệp tạm thời sẽ là:

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

Tập tin tạm thời cũng có thể bị xóa, mặc dù mỗi lần điều này xảy ra, nội dung của nó sẽ bị ghi đè.


cảm ơn bạn. Bạn có thể vui lòng giải thích cho tôi từng bước bash thực hiện? Tôi không thể tưởng tượng nó hoạt động như thế nào.
dorinand

tail -50 /home/pi/Documents/test >/tmp/foo && cat /tmp/foo >/home/pi/Documents/test
steve

1
lưu ý rằng điều này sẽ không hoạt động nếu logfile vẫn mở bởi quá trình ghi nhật ký (sẽ tiếp tục đăng nhập vào tệp gốc, đã bị xóa). tempfile + di chuyển dẫn đến một inode mới (phá vỡ mọi liên kết cứng) và có thể là chủ sở hữu hoặc perm khác nhau. tail ... > temp ; cat temp > orig ; rm -f tempcông trinh.
cas

4

Vì bạn đã thấy vấn đề chính với chuyển hướng shell, đây là một cách khác để cắt tỉa một tệp thành 50 dòng cuối cùng của nó:

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

Công việc khó khăn được thực hiện bởi (GNU) sed với -itính năng "chỉnh sửa tại chỗ", hoạt động dưới vỏ bọc bằng cách tạo đầu ra trong một tệp tạm thời. Phần còn lại của dòng thiết lập toán cho hoạt động của sed, cụ thể là:

  1. đếm các dòng trong tệp ( wc), sau đó trừ 50; gán nó cho n.
  2. nếu n là dương, chạy lệnh sed để xóa các dòng từ 1 đến n.

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

printfđược sử dụng để lệnh ống (một trên mỗi dòng) vào ed. Các edlệnh là:

  • 1,$-50d - xóa tất cả nhưng 50 dòng cuối cùng
  • w - ghi tập tin sửa đổi trở lại đĩa

Không có chuyển hướng liên quan, vì vậy trình bao không thể ghi đè lên tệp đầu ra trước khi nó được đọc.

Ngoài ra, không giống như hầu hết các hình thức chỉnh sửa "tại chỗ" (thường chỉ mô phỏng chỉnh sửa "tại chỗ" bằng cách tạo tệp tạm thời và sau đó đổi tên thành bản gốc), edthực tế chỉnh sửa tệp gốc - vì vậy nó giữ nguyên nút ( và chủ sở hữu, nhóm và quyền - tempfile + mv sẽ luôn thay đổi inode và có thể thay đổi các tùy chọn khác tùy theo hoàn cảnh).


4

Trên một bản nhạc hơi khác, bạn có thể sử dụng logrotate(8)để sao lưu các tệp nhật ký thường xuyên để tăng dần các tệp được đặt tên và sau đó xóa các tệp cũ.

Đây là cách các tệp nhật ký hệ thống chính được quản lý để ngăn chúng phát triển quá lâu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.