Tôi đang cố gắng để giữ một thư mục chứa đầy các tệp nhật ký. Hàng đêm, tôi muốn xóa tất cả trừ 10 cái gần đây nhất. Làm thế nào tôi có thể làm điều này trong một lệnh duy nhất?
Tôi đang cố gắng để giữ một thư mục chứa đầy các tệp nhật ký. Hàng đêm, tôi muốn xóa tất cả trừ 10 cái gần đây nhất. Làm thế nào tôi có thể làm điều này trong một lệnh duy nhất?
Câu trả lời:
Đối với một giải pháp di động và đáng tin cậy, hãy thử điều này:
ls -1tr | head -n -10 | xargs -d '\n' rm -f --
Các tail -n -10
cú pháp trong một trong những câu trả lời khác dường như không làm việc ở khắp mọi nơi (tức là, không phải trên hệ thống RHEL5 của tôi).
Và sử dụng $()
hoặc ``
trên dòng lệnh rm
có nguy cơ
xargs
khắc phục cả hai vấn đề này bởi vì nó sẽ tự động tìm ra có bao nhiêu đối số có thể vượt qua trong giới hạn ký tự và với -d '\n'
nó sẽ chỉ phân tách ở ranh giới dòng của đầu vào. Về mặt kỹ thuật, điều này vẫn có thể gây ra sự cố cho tên tệp có dòng mới, nhưng nó ít phổ biến hơn tên tệp có khoảng trắng và cách duy nhất xung quanh dòng mới sẽ phức tạp hơn nhiều, có thể liên quan đến ít nhất là awk, nếu không nói là perl.
Nếu bạn không có xargs (hệ thống AIX cũ, có thể?) Bạn có thể biến nó thành một vòng lặp:
ls -1tr | head -n -10 | while IFS= read -r f; do
rm -f "$f"
done
Điều này sẽ chậm hơn một chút vì nó sinh ra một rm
tệp riêng cho mỗi tệp, nhưng vẫn sẽ tránh được cảnh báo 1 và 2 ở trên (nhưng vẫn phải chịu các dòng mới trong tên tệp).
head(1)
trang người đàn ông:-n, --lines=[-]K print the first K lines instead of the first 10; with the leading '-', print all but the last K lines of each file
head
và xargs
đưa ra lỗi. Các tùy chọn chính xác là head -n 10
và xargs rm -f
. Toàn lệnh làls -1tr ./ | head -n 10 | xargs rm -rf
ls -1tr
là số MỘT chứ không phải chữ "L".
Mã bạn muốn đưa vào tập lệnh của mình là
rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)
Các -1
(số một) tùy chọn in mỗi tập tin trên một dòng duy nhất, để được an toàn. Các -f
tùy chọn để rm
cho nó để bỏ qua các file không tồn tại khi ls
lợi nhuận không có gì.
/path/to/your/logs
chỉ là bù đắp cho bạn để đi vào con đường chính xác. Để tìm lỗi thực hiện các phần ls -t /path/...
và ls -t /path/... | tail -n +11
một mình và kiểm tra xem kết quả có đúng không.
+
trước số. Nó làm cho tail
không in n phần tử cuối cùng mà tất cả các phần tử bắt đầu từ thứ n. Tôi đã kiểm tra lại và lệnh chắc chắn chỉ xóa các phần tử cũ hơn 10 tệp gần đây nhất trong mọi trường hợp.
ls
in tên tệp chứ không phải đường dẫn nên bạn rm -f
sẽ cố xóa các tệp trong thư mục hiện tại
Rõ ràng phân tích ls
là xấu xa .
Nếu mỗi tệp được tạo hàng ngày và bạn muốn giữ các tệp được tạo trong vòng 10 ngày qua, bạn có thể làm:
find /path/to/files -mtime 10 -delete
Hoặc nếu mỗi tệp được tạo tùy ý:
find /path/to/files -maxdepth 1 -type f -printf '%Ts\t%P\n' | sort -n | head -n -10 | cut -f 2- | xargs rm -rf
-mtime 10 -delete
chỉ xóa các tệp được sửa đổi chính xác 10 ngày trước. Các tập tin cũ hơn sẽ không bị xóa. -mtime +11 -delete
sẽ xóa các tệp đã được sửa đổi 11 ngày trở lên để lại 10 ngày cuối cùng của tệp nhật ký.
%p
thay vì %P
là cần thiết trên printf
để các tập tin có đường dẫn đầy đủ. Nếu không rm -rf
thì không hoạt động.
Tôi đã sửa đổi cách tiếp cận của Isaac một chút.
Bây giờ nó hoạt động với một đường dẫn mong muốn:
ls -d -1tr /path/to/folder/* | head -n -10 | xargs -d '\n' rm -f
Từ đây :
#! /bin/sh
# keepnewest
#
# Simple directory trimming tool to handle housekeeping
# Scans a directory and deletes all but the N newest files
#
# Usage: cleanup <dir> <number of files to keep>
#
# v 1.0 Piers Goodhew 1/mar/2007. No rights retained.
if [ $# -ne 2 ]; then
echo 1>&2 "Usage: $0 <dir> <number of files to keep>"
exit 1
fi
cd $1
files_in_dir=`ls | wc -l`
files_to_delete=`expr $files_in_dir - $2`
if [ $files_to_delete -gt 0 ]; then
ls -t | tail -n $files_to_delete | xargs rm
if [ $? -ne 0 ]; then
echo "An error ocurred deleting the files"
exit 1
else
echo "$files_to_delete file(s) deleted."
fi
else
echo "nothing to delete!"
fi
Trong Bash bạn có thể thử:
ls -1t | (i=0; while read f; do
if [ $i -lt 10 ]; then
((i++))
continue
else
rm -f "$f"
fi
done)
Điều này bỏ qua 10 als mới nhất xóa phần còn lại. logrotate có thể tốt hơn, tôi chỉ muốn sửa các câu trả lời liên quan đến vỏ sai.
không chắc chắn điều này sẽ giúp được ai, nhưng để tránh các vấn đề tiềm ẩn với các ký tự rủng rỉnh tôi chỉ sử dụng ls
để thực hiện sắp xếp nhưng sau đó sử dụng các tệp inode
để xóa.
Đối với thư mục hiện tại, tệp này giữ 10 tệp gần đây nhất dựa trên thời gian sửa đổi.
ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;
Tôi cần một giải pháp tao nhã cho busybox (bộ định tuyến), tất cả các giải pháp xargs hoặc mảng đều vô dụng đối với tôi - không có lệnh nào như vậy có sẵn ở đó. tìm và mtime không phải là câu trả lời thích hợp vì chúng ta đang nói về 10 mục và không nhất thiết là 10 ngày. Câu trả lời của Espo là câu trả lời ngắn gọn và sạch nhất và có khả năng nhất.
Lỗi với khoảng trắng và khi không có tệp nào bị xóa, cả hai đều được giải quyết theo cách tiêu chuẩn:
rm "$(ls -td *.tar | awk 'NR>7')" 2>&-
Phiên bản giáo dục hơn một chút: Chúng tôi có thể làm tất cả nếu chúng tôi sử dụng awk khác nhau. Thông thường, tôi sử dụng phương thức này để truyền (trả về) các biến từ awk sang sh. Khi chúng ta đọc tất cả thời gian không thể thực hiện được, tôi xin khác: đây là phương pháp.
Ví dụ cho các tệp .tar không có vấn đề liên quan đến khoảng trắng trong tên tệp. Để kiểm tra, thay thế "rm" bằng "ls".
eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')
Giải trình:
ls -td *.tar
liệt kê tất cả các tập tin .tar được sắp xếp theo thời gian. Để áp dụng cho tất cả các tệp trong thư mục hiện tại, hãy xóa phần "d * .tar"
awk 'NR>7...
bỏ qua 7 dòng đầu tiên
print "rm \"" $0 "\""
xây dựng một dòng: rm "tên tệp"
eval
thực hiện nó
Vì chúng tôi đang sử dụng rm
, tôi sẽ không sử dụng lệnh trên trong một tập lệnh! Cách sử dụng khôn ngoan là:
(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))
Trong trường hợp sử dụng ls -t
lệnh sẽ không gây hại gì cho các ví dụ ngớ ngẩn như: touch 'foo " bar'
và touch 'hello * world'
. Không phải là chúng ta từng tạo ra những tập tin có tên như vậy trong đời thực!
Sidenote. Nếu chúng ta muốn truyền một biến cho sh theo cách này, chúng ta chỉ cần sửa đổi bản in:
print "VarName="$1
để đặt biến VarName
thành giá trị của $1
. Nhiều biến có thể được tạo trong một lần. Điều này VarName
trở thành một biến sh bình thường và có thể được sử dụng bình thường trong một tập lệnh hoặc shell sau đó. Vì vậy, để tạo các biến với awk và đưa chúng trở lại trình bao:
eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"