Saya mencoba untuk menjaga direktori penuh dengan file log yang dapat dikelola. Nightly, saya ingin menghapus semua kecuali 10 yang terbaru. Bagaimana saya bisa melakukan ini dalam satu perintah?
Saya mencoba untuk menjaga direktori penuh dengan file log yang dapat dikelola. Nightly, saya ingin menghapus semua kecuali 10 yang terbaru. Bagaimana saya bisa melakukan ini dalam satu perintah?
Jawaban:
Untuk solusi portabel dan andal, coba ini:
ls -1tr | head -n -10 | xargs -d '\n' rm -f --
The tail -n -10sintaks di salah satu jawaban yang lain tampaknya tidak bekerja di mana-mana (yaitu, bukan pada sistem RHEL5 saya).
Dan menggunakan $()atau ``pada baris perintah rmmenjalankan risiko
xargsmemperbaiki kedua masalah ini karena secara otomatis akan mencari tahu berapa banyak argumen yang dapat dilewati dalam batas karakter, dan dengan -d '\n'itu hanya akan terpecah pada batas garis input. Secara teknis ini masih dapat menyebabkan masalah untuk nama file dengan baris baru di dalamnya, tetapi itu jauh lebih umum daripada nama file dengan spasi, dan satu-satunya cara di sekitar baris baru akan jauh lebih rumit, mungkin melibatkan setidaknya awk, jika tidak perl.
Jika Anda tidak memiliki xargs (sistem AIX lama, mungkin?) Anda dapat membuatnya menjadi loop:
ls -1tr | head -n -10 | while IFS= read -r f; do
rm -f "$f"
done
Ini akan sedikit lebih lambat karena memunculkan terpisah rmuntuk setiap file, tetapi masih akan menghindari peringatan 1 dan 2 di atas (tetapi masih menderita baris baru dalam nama file).
head(1)halaman manual:-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
headdan xargsberikan kesalahan. Opsi yang benar adalah head -n 10dan xargs rm -f. Perintah penuh adalahls -1tr ./ | head -n 10 | xargs rm -rf
ls -1trapakah nomor SATU bukan huruf "L".
Kode yang ingin Anda sertakan dalam skrip Anda adalah
rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)
Opsi -1(numerik) mencetak setiap file pada satu baris, agar aman. The -fpilihan untuk rmmengatakan itu untuk mengabaikan file tidak ada ketika lskembali apa-apa.
/path/to/your/logshanya dibuat untuk Anda memasuki jalan yang benar. Untuk menemukan bug mengeksekusi bagian ls -t /path/...dan ls -t /path/... | tail -n +11sendirian dan memeriksa apakah hasilnya benar.
+sebelum nomornya. Itu membuat tailtidak mencetak elemen n terakhir tetapi semua elemen dimulai dari tanggal n. Saya check in lagi dan perintahnya pasti menghapus hanya elemen yang lebih tua dari 10 file terbaru dalam semua keadaan.
lsmencetak nama file, bukan jalan sehingga Anda rm -fakan mencoba untuk menghapus file dalam direktori saat ini
Ternyata penguraian lsitu jahat .
Jika setiap file dibuat setiap hari dan Anda ingin menyimpan file yang dibuat dalam 10 hari terakhir yang dapat Anda lakukan:
find /path/to/files -mtime 10 -delete
Atau jika setiap file dibuat secara sewenang-wenang:
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 -deletehanya menghapus file yang dimodifikasi persis 10 hari yang lalu. File yang lebih lama tidak akan dihapus. -mtime +11 -deleteakan menghapus file yang telah dimodifikasi 11 hari atau lebih yang lalu meninggalkan 10 hari terakhir file log.
%pbukannya %Pdiperlukan pada printfagar file mendapat jalur penuh. Kalau rm -rftidak, tidak akan berhasil.
Saya sedikit memodifikasi pendekatan Isaac .
Sekarang bekerja dengan jalur yang diinginkan:
ls -d -1tr /path/to/folder/* | head -n -10 | xargs -d '\n' rm -f
Dari sini :
#! /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
Di Bash Anda dapat mencoba:
ls -1t | (i=0; while read f; do
if [ $i -lt 10 ]; then
((i++))
continue
else
rm -f "$f"
fi
done)
Ini melompati 10 juga yang terbaru menghapus sisanya. logrotate mungkin lebih baik, saya hanya ingin memperbaiki jawaban terkait shell yang salah.
tidak yakin ini akan membantu siapa pun selain untuk menghindari potensi masalah dengan karakter miring saya hanya digunakan lsuntuk melakukan penyortiran tetapi kemudian menggunakan file inodeuntuk menghapus.
Untuk direktori saat ini, ini menyimpan 10 file terbaru berdasarkan waktu modifikasi.
ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;
Saya membutuhkan solusi elegan untuk busybox (router), semua xargs atau solusi array tidak berguna bagi saya - tidak ada perintah seperti itu tersedia di sana. temukan dan mtime bukanlah jawaban yang tepat karena kita berbicara tentang 10 item dan belum tentu 10 hari. Jawaban Espo adalah yang terpendek dan terbersih dan kemungkinan yang paling tidak terbalik.
Kesalahan dengan spasi dan ketika tidak ada file yang akan dihapus keduanya diselesaikan dengan cara standar:
rm "$(ls -td *.tar | awk 'NR>7')" 2>&-
Versi yang sedikit lebih edukatif: Kita bisa melakukan semuanya jika kita menggunakan awk secara berbeda. Biasanya, saya menggunakan metode ini untuk mengirimkan (mengembalikan) variabel dari awk ke sh. Ketika kita membaca semua waktu yang tidak dapat dilakukan, saya mohon berbeda: di sini adalah metode.
Contoh untuk file tar. Tanpa masalah tentang spasi dalam nama file. Untuk menguji, ganti "rm" dengan "ls".
eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')
Penjelasan:
ls -td *.tardaftar semua file tar. Diurutkan berdasarkan waktu. Untuk menerapkan ke semua file di folder saat ini, hapus bagian "d * .tar"
awk 'NR>7... melompati 7 baris pertama
print "rm \"" $0 "\"" membangun sebuah baris: rm "nama file"
eval jalankan itu
Karena kita menggunakan rm, saya tidak akan menggunakan perintah di atas dalam skrip! Penggunaan Wiser adalah:
(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))
Dalam hal menggunakan ls -tperintah tidak akan membahayakan contoh konyol seperti: touch 'foo " bar'dan touch 'hello * world'. Bukan berarti kami pernah membuat file dengan nama seperti itu di kehidupan nyata!
Sidenote. Jika kita ingin melewatkan variabel ke sh dengan cara ini, kita cukup memodifikasi cetakan:
print "VarName="$1
untuk mengatur variabel VarNameke nilai $1. Beberapa variabel dapat dibuat dalam sekali jalan. Ini VarNamemenjadi variabel sh normal dan biasanya dapat digunakan dalam skrip atau shell sesudahnya. Jadi, untuk membuat variabel dengan awk dan mengembalikannya ke shell:
eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"
Berdasarkan respons Isaac Freeman, tetapi bekerja pada direktori apa pun:
ls -1tr $PATH_TO_DELETE/* | head -n -10 | xargs -d '\n' rm -f --
Anda juga dapat mengatur awalan, seperti $PATH_TO_DELETE/testFi*
Jika Anda menggunakan *setelah PATH lsakan menampilkan nama file absolut, setidaknya di "my" bash :)