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 -10
sintaks di salah satu jawaban yang lain tampaknya tidak bekerja di mana-mana (yaitu, bukan pada sistem RHEL5 saya).
Dan menggunakan $()
atau ``
pada baris perintah rm
menjalankan risiko
xargs
memperbaiki 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 rm
untuk 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
head
dan xargs
berikan kesalahan. Opsi yang benar adalah head -n 10
dan xargs rm -f
. Perintah penuh adalahls -1tr ./ | head -n 10 | xargs rm -rf
ls -1tr
apakah 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 -f
pilihan untuk rm
mengatakan itu untuk mengabaikan file tidak ada ketika ls
kembali apa-apa.
/path/to/your/logs
hanya dibuat untuk Anda memasuki jalan yang benar. Untuk menemukan bug mengeksekusi bagian ls -t /path/...
dan ls -t /path/... | tail -n +11
sendirian dan memeriksa apakah hasilnya benar.
+
sebelum nomornya. Itu membuat tail
tidak 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.
ls
mencetak nama file, bukan jalan sehingga Anda rm -f
akan mencoba untuk menghapus file dalam direktori saat ini
Ternyata penguraian ls
itu 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 -delete
hanya menghapus file yang dimodifikasi persis 10 hari yang lalu. File yang lebih lama tidak akan dihapus. -mtime +11 -delete
akan menghapus file yang telah dimodifikasi 11 hari atau lebih yang lalu meninggalkan 10 hari terakhir file log.
%p
bukannya %P
diperlukan pada printf
agar file mendapat jalur penuh. Kalau rm -rf
tidak, 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 ls
untuk melakukan penyortiran tetapi kemudian menggunakan file inode
untuk 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 *.tar
daftar 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 -t
perintah 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 VarName
ke nilai $1
. Beberapa variabel dapat dibuat dalam sekali jalan. Ini VarName
menjadi 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
ls
akan menampilkan nama file absolut, setidaknya di "my" bash :)