Làm thế nào để bạn chỉ giữ n dòng cuối cùng của một tệp nhật ký?


18

Một đoạn script tôi đã viết sẽ làm một cái gì đó và cuối cùng, nối thêm một số dòng vào logfile của chính nó. Tôi chỉ muốn giữ lại n dòng cuối cùng (giả sử là 1000 dòng) của logfile. Điều này có thể được thực hiện ở phần cuối của kịch bản theo cách này:

tail -n 1000 myscript.log > myscript.log.tmp
mv -f myscript.log.tmp myscript.log

Nhưng có một giải pháp sạch sẽ và thanh lịch hơn? Có lẽ hoàn thành thông qua một lệnh duy nhất?


logrotatelà giải pháp tao nhã
Ipor Sircer

1
Tôi đã nghĩ về nó, nhưng cấu hình logrotate sẽ dài hơn chính kịch bản ...
dr01

Nếu logrotate là quá mức cần thiết, giải pháp của bạn là thanh lịch như nó được. Với sed / awk, bạn có thể thực hiện nó trong một dòng nhưng không phải không có tệp tạm thời trong nội bộ, vì vậy nó có thể không hiệu quả hơn và có thể ít đọc hơn.
kba đứng với Monica

Câu trả lời:


28

Có thể như thế này, nhưng như những người khác đã nói, tùy chọn an toàn nhất là tạo ra một tệp mới và sau đó di chuyển tệp đó để ghi đè lên bản gốc.

Phương thức bên dưới tải các dòng vào BASH, do đó tùy thuộc vào số lượng dòng từ tailđó, điều đó sẽ ảnh hưởng đến việc sử dụng bộ nhớ của trình bao cục bộ để lưu trữ nội dung của các dòng nhật ký.

Bên dưới cũng loại bỏ các dòng trống nếu chúng tồn tại ở cuối tệp nhật ký (do hành vi đánh giá BASH "$(tail -1000 test.log)"), do đó, không đưa ra một cắt ngắn thực sự chính xác 100% trong tất cả các tình huống, nhưng tùy thuộc vào tình huống của bạn, có thể là đủ.

$ wc -l myscript.log
475494 myscript.log

$ echo "$(tail -1000 myscript.log)" > myscript.log

$ wc -l myscript.log
1000 myscript.log

Thông minh. Tôi đã đánh dấu đây là câu trả lời được chấp nhận vì nó không yêu cầu cài đặt các công cụ bổ sung. Tôi ước tôi có thể chấp nhận cả câu trả lời của bạn và @ John1024.
dr01

Cuộc gọi của bạn. Tôi đã nâng cấp giải pháp bọt biển vì tôi không biết về nó và nó được đảm bảo không gây rối với các dòng nhật ký trống. Giải pháp này có tiềm năng để làm điều đó, tùy thuộc vào nội dung tệp nhật ký.
parkamark

21

Các tiện ích spongeđược thiết kế chỉ dành cho trường hợp này. Nếu bạn đã cài đặt nó, thì hai dòng của bạn có thể được viết:

tail -n 1000 myscript.log | sponge myscript.log

Thông thường, đọc từ một tệp cùng lúc mà bạn đang viết cho nó là không đáng tin cậy. spongegiải quyết điều này bằng cách không viết cho myscript.logđến khi tailđọc xong và kết thúc đường ống.

Tải về

Để cài đặt spongetrên hệ thống giống như Debian:

apt-get install moreutils

Để cài đặt spongetrên hệ thống RHEL / CentOS, hãy thêm repo EPEL và sau đó làm:

yum install moreutils

Tài liệu

Từ man sponge:

spongeđọc đầu vào tiêu chuẩn và ghi nó ra tập tin được chỉ định. Không giống như chuyển hướng shell, spongetiếp thu tất cả đầu vào của nó trước khi ghi tệp đầu ra. Điều này cho phép xây dựng các đường ống đọc và ghi vào cùng một tệp.


2
+1 Cảm ơn, tôi không biết sponge. Rất hữu ích cho tất cả những người đã học theo cách khó mà bạn không thể làm được sort importantfile.txt > importantfile.txt:)
dr01

4

chắc chắn "đuôi + mv" tốt hơn nhiều! Nhưng đối với gnu sed chúng ta có thể thử

sed -i -e :a -e '$q;N;101,$D;ba' log

3

Đối với hồ sơ, với edbạn có thể làm một cái gì đó như

ed -s infile <<\IN
0r !tail -n 1000 infile
+1,$d
,p
q
IN

Điều này sẽ mở ra infilevà xuất hiện rtrong đầu ra của tail -n 1000 infile(nghĩa là nó chèn đầu ra đó trước dòng thứ 1) và sau đó xóa từ dòng đầu tiên đến cuối tập tin. Thay thế ,pbằng wđể chỉnh sửa các tập tin tại chỗ.
Hãy ghi nhớ rằng edcác giải pháp không phù hợp với các tệp lớn.


0

Những gì bạn có thể làm trong kịch bản của mình là triển khai logic xoay vòng nhật ký. Thực hiện tất cả việc đăng nhập thông qua một chức năng:

log()
{
   ...
}

Chức năng này, trước tiên, thực hiện một số thứ như:

printf "%s\n" "$*" >> logfile

sau đó, nó kiểm tra kích thước của tệp hoặc bằng cách nào đó quyết định rằng tệp yêu cầu xoay. Tại thời điểm đó, tệp logfile.1, nếu nó tồn tại, bị xóa, tệp logfile.0, nếu nó tồn tại, được đổi tên thành logfile.1logfileđược đổi tên thành logfile.0.

Quyết định có nên xoay hay không dựa trên bộ đếm được duy trì trong chính tập lệnh. Khi nó chạm 1000, nó được đặt lại về 0.

Nếu luôn luôn cắt xén nghiêm ngặt đến 1000 dòng là một yêu cầu, tập lệnh có thể đếm số lượng dòng trong tệp nhật ký khi nó khởi động và khởi tạo bộ đếm tương ứng (hoặc nếu số lượng đã đáp ứng hoặc vượt quá 1000, hãy thực hiện xoay vòng ngay lập tức).

Hoặc bạn có thể có được kích thước, chẳng hạn như với wc -c logfilevà thực hiện xoay vòng dựa trên việc vượt quá một kích thước nhất định. Bằng cách này, tập tin không bao giờ phải được quét để xác định điều kiện.


0

Tôi đã sử dụng, thay vì mv, cplệnh để đạt được nó rằng bạn có thể có một số logfile ngay tại nơi Phần mềm đang chạy. Có thể trong thư mục nhà người dùng khác hoặc trong thư mục ứng dụng và có tất cả các bản ghi ở một nơi dưới dạng liên kết cứng. Nếu bạn sử dụngmv lệnh, bạn sẽ mất liên kết cứng. Nếu bạn sử dụng cplệnh thay vì bạn sẽ giữ liên kết cứng này.

mã của tôi là một cái gì đó như:

TMP_FILE="$(mktemp "${TMPFILENAME}.XXX")"

for FILE in "${LOGFILE_DIR}"/* ; do
    tail -n $MAXLINES "${FILE}" > "${TMP_FILE}"
    if [ $(ls -g "${TMP_FILE}" | awk '{print $4}') -lt $(ls -g "${FILE}" | awk '{print $4}') ] ; then
        cp "${TMP_FILE}" "${FILE}"
    fi
done   

Vì vậy, nếu các tệp nằm trên cùng một Hệ thống tệp, bạn cũng có thể cung cấp một số quyền khác nhau cho người dùng và trong ${LOGFILE_DIR} bạn sửa đổi độ dài như tôi.

Nếu nó là mv lệnh bạn mất liên kết cứng giữa các tệp và do đó tệp thứ hai của bạn không được kết nối nhiều hơn với tệp đầu tiên - có thể được đặt ở một số nơi khác.

Nếu ở nơi khác, bạn không cho phép ai đó xóa tệp thì nhật ký của bạn sẽ ở cùng nhau và được kiểm soát tốt thông qua tập lệnh của riêng bạn.

logrotatecó lẽ đẹp hơn Nhưng tôi hài lòng với giải pháp này.

Đừng bị làm phiền bởi "" nhưng trong trường hợp của tôi, có một số tệp có dấu cách và các chữ cái đặc biệt khác và nếu tôi không thực hiện "" xung quanh hoặc {} thì toàn bộ lô không hoạt động tốt.

Ví dụ: có một Dir nơi các tệp cũ hơn được tự động nén vào một OLDFILE.zipvà mọi thứ được nén cũng được liệt kê trong Tệp, .zip_logvì vậy .zip_logcũng có trong Dir này nhưng trong LOGFILE_DIRTôi đã có:

ln .zip_log "${LOGFILE_DIR}/USER_ZIP_log"

các tập tin bằng nhau vì nó là một liên kết cứng.

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.