Bir dizini yönetilebilir günlük dosyalarıyla dolu tutmaya çalışıyorum. Gecelik, en son 10 hariç hepsini silmek istiyorum. Bunu tek bir komutla nasıl yapabilirim?
Bir dizini yönetilebilir günlük dosyalarıyla dolu tutmaya çalışıyorum. Gecelik, en son 10 hariç hepsini silmek istiyorum. Bunu tek bir komutla nasıl yapabilirim?
Yanıtlar:
Taşınabilir ve güvenilir bir çözüm için şunu deneyin:
ls -1tr | head -n -10 | xargs -d '\n' rm -f --
tail -n -10Diğer yanıtları birinde sözdizimi (benim RHEL5 sistemlerde, yani) her yerde işe görünmüyor.
Ve komut satırında $()veya ``komutunun kullanılması rmriski
xargsBu problemlerin her ikisini de düzeltir, çünkü otomatik olarak karakter sınırlaması içinde kaç tane hata geçebileceğini ve -d '\n'bunun yalnızca girişin sınırında bölüneceğini otomatik olarak çözecektir . Teknik olarak bu, içinde yeni bir satır bulunan dosya isimleri için sorunlara neden olabilir, ancak boşluk içeren dosya adlarından çok daha az yaygındır ve yeni satırların etrafındaki tek yol perl değilse, muhtemelen en azından awk içeren çok daha karmaşık olacaktır.
Eğer xargs'ınız yoksa (eski AIX sistemleri, belki de?) Bunu bir döngü haline getirebilirsiniz:
ls -1tr | head -n -10 | while IFS= read -r f; do
rm -f "$f"
done
Bu, rmher dosya için ayrı bir boşluk bıraktığı için biraz daha yavaş olacaktır, ancak yine de yukarıdaki 1 ve 2 no'lu uyarılardan kaçınacaktır (ancak dosya adlarındaki yeni satırlardan hala muzdariptir).
head(1)Man sayfadan:-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
headve xargsvermek hataları. Doğru seçenekler head -n 10ve xargs rm -f. Tam komutls -1tr ./ | head -n 10 | xargs rm -rf
ls -1trsayı TEK harfi değil "L" dir.
Komut dosyasına eklemek istediğiniz kod
rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)
-1(Sayısal bir) seçeneği baskılar tek bir satırda her dosya, güvenli olmak. -fSeçeneği rmo zaman için var olmayan dosyaları görmezden söyler lsdöner şey.
/path/to/your/logs, doğru yola girmeniz için hazırlanmıştır. Hatayı bulmak için parçaları tek başınıza çalıştırın ls -t /path/...ve ls -t /path/... | tail -n +11sonucun doğru olup olmadığını kontrol edin.
+önce dikkat et. Bu hale tailson n elemanını ama n'th itibaren tüm unsurları baskı değil. Tekrar kontrol ettim ve komut kesinlikle her koşulda en son 10 dosyadan daha eski olan öğeleri kaldırmalı.
lsbir yol değil, bir dosya adı yazdırır, böylece rm -fgeçerli dizindeki dosyaları kaldırmaya çalışacaksınız
Görünüşe göre ayrıştırma lskötüdür .
Her dosya günlük olarak oluşturulursa ve son 10 gün içinde oluşturulan dosyaları saklamak istiyorsanız, şunları yapabilirsiniz:
find /path/to/files -mtime 10 -delete
Veya her dosya keyfi oluşturulursa:
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 -deleteyalnızca tam olarak 10 gün önce değiştirilmiş dosyaları siler. Daha eski dosyalar silinmeyecek. -mtime +11 -deleteson 10 gün günlük dosyalarından çıkmadan 11 gün veya daha önce değiştirilmiş dosyaları silecektir.
%pyerine dosyaların tam yolunu %Palabilmesi için bunun yerine kullanılması gerektiğini düşünüyorum printf. Aksi takdirde rm -rfişe yaramaz.
Ben modifiye Isaac yaklaşımını biraz.
Şimdi istenen yolla çalışıyor:
ls -d -1tr /path/to/folder/* | head -n -10 | xargs -d '\n' rm -f
Gönderen burada :
#! /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
Bash'de deneyebilirsiniz:
ls -1t | (i=0; while read f; do
if [ $i -lt 10 ]; then
((i++))
continue
else
rm -f "$f"
fi
done)
Bu atlar 10 en yeni als geri kalanını siler. logrotate daha iyi olabilir, sadece yanlış kabuk ile ilgili cevapları düzeltmek istiyorum.
Bunun kimseye yardımcı olacağından emin değilim, ama riskli karakterlerle ilgili olası sorunları önlemek için sadece lssıralama yapmak için kullandım, sonra dosyaları inodesilmek için kullandım.
Geçerli dizin için, bu değişiklik zamanına bağlı olarak en son 10 dosyayı tutar.
ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;
Meşgul kutusu (yönlendirici) için zarif bir çözüme ihtiyacım vardı, tüm xargs veya dizi çözümleri bana işe yaramadı - orada böyle bir komut yoktu. 10 maddeden bahsettiğimiz ve mutlaka 10 gün olduğu için mtime bul ve doğru cevap değil. Espo'nun cevabı en kısa ve en temiz ve muhtemelen en farklı olanıydı.
Boşluklarla ilgili hata ve hiçbir dosya silinmeyecekse her ikisi de standart yoldan çözülür:
rm "$(ls -td *.tar | awk 'NR>7')" 2>&-
Biraz daha eğitici versiyon: Eğer awk farklı kullanırsak hepsini yapabiliriz. Normalde, bu yöntemi değişkenleri awk'den sh'ye (dönüş) geçirmek için kullanırım. Yapamadığım her zaman okuduğumuzda, farklı olmak için yalvarırım: işte yöntem.
Dosya adındaki boşluklarla ilgili problemsiz olan .tar dosyaları için örnek. Test etmek için, "rm" yi "ls" ile değiştirin.
eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')
Açıklama:
ls -td *.tarZamana göre sıralanmış tüm .tar dosyalarını listeler. Geçerli klasördeki tüm dosyalara uygulamak için "d * .tar" bölümünü kaldırın
awk 'NR>7... ilk 7 satırı atlar
print "rm \"" $0 "\"" bir satır oluşturur: rm "dosya adı"
eval yürütür
Kullandığımızdan beri rmyukarıdaki komutu bir komut dosyasında kullanmazdım! Wiser kullanımı:
(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))
Kullanılması durumunda ls -t: Böyle saçma örnekleri olarak üzerinde herhangi bir zarar vermez komutu touch 'foo " bar've touch 'hello * world'. Gerçek hayatta böyle isimlerle dosyalar yarattığımızdan değil!
Kenar notu. Eğer bir değişkeni sh'a bu yolla iletmek isteseydik, baskıyı değiştiririz:
print "VarName="$1
değişkeni VarNamedeğerini ayarlamak için $1. Tek seferde birden fazla değişken oluşturulabilir. Bu VarNamenormal bir sh değişkeni olur ve daha sonra normal olarak bir betikte veya kabukta kullanılabilir. Dolayısıyla, awk ile değişkenler oluşturmak ve onları kabuğa geri vermek için:
eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"
Isaac Freeman'ın cevabına göre, ancak herhangi bir dizinde çalışıyor:
ls -1tr $PATH_TO_DELETE/* | head -n -10 | xargs -d '\n' rm -f --
Ayrıca, bir önek de ayarlayabilirsiniz. $PATH_TO_DELETE/testFi*
Mutlak dosya adlarını *çıkardıktan sonra kullanırsanız PATH ls, en azından "my" bash :) 'da