Linux'taki en yeni 10 dosyayı nasıl silebilirim?


49

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?


3
logrotate'e bir göz atın
knittl


@michael Tartışmam ilk olarak oluşturulduysa, benimkinin kopyası nasıl olabilir?
dev4life

@ovaherenow "senin"? Her iki soruda da adınızı göremiyorum, bu yüzden hangisini kastettiğinizden emin değilim. Benim yorumum hangisinin diğerinin bir kopyası olduğunu bile göstermiyor. Ama önemli değil - sadece bir bağlantı, bir yorum. Her iki soruya veya her iki soruya da eklenebilir. Birini veya diğerini kopya olarak işaretlemek bir başkasına (yönetici) bağlıdır. Hiçbir aşırıcılık çabukluğu amaçlanmadı ve algılanmaması gerekiyordu. Hangi sorunun ilk önce olduğundan daha önemli, hangi sorunun en iyi cevaba sahip olduğu - yine bağlantı bu tartışmayı kolaylaştırıyor, cevabı belirleyemiyor.
michael

@michael wow. Bu gerçekten garip. Bu konu benim tarafımdan açılmış, ancak açıkçası kullanıcı adım değil. Ancak bu konu hakkında bilgilendiriliyorum.
dev4life

Yanıtlar:


58

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

  1. dosya adlarını boşlukla bölme ve
  2. maksimum komut satırı karakter sınırını aştı.

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).


@HaukeLaging: 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
Isaac Freeman

Solaris 10 üzerinde headve xargsvermek hataları. Doğru seçenekler head -n 10ve xargs rm -f. Tam komutls -1tr ./ | head -n 10 | xargs rm -rf
DmitrySandalov

1
Not ls -1trsayı TEK harfi değil "L" dir.
shonky linux kullanıcısı

1
Ayrıca yeni satırların nadir fakat harici dosya adlarında geçerli karakterler olduğu da belirtilmelidir. Bu, eğer "o" ve "that \ nthing" dosyalarına sahipseniz, bu script "that \ nthing" e basarsa, "that" 'ı silecek, "şeyi" silemediğinde hata çıkacak ve "o \ nthing" (amaçlanan hedef) etkilenmemiş.
Saat

1
@IacacFreeman Kötü tavsiyemi sildim, şerefe.
Walf

20

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.


Orijinal poster burada. Bu komutu denedim ama işe yaramadı - "rm: missing operand" hatasını alıyorum
user75814

2
Doğru yolu kullandın mı? Açıkçası /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.
Daniel Böhmer

1
@HaukeLaging Bir şeyler yanlış yaptığınıza eminim. Sayıdan +ö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ı.
Daniel Böhmer

@halo Gerçekten de üzgünüm.
Hauke,

2
Cevabınız çok tehlikeli olduğunu düşünüyorum lsbir yol değil, bir dosya adı yazdırır, böylece rm -fgeçerli dizindeki dosyaları kaldırmaya çalışacaksınız
Jürgen Steinblock

14

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

5
-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.
Markus

1
Bunun %pyerine dosyaların tam yolunu %Palabilmesi için bunun yerine kullanılması gerektiğini düşünüyorum printf. Aksi takdirde rm -rfişe yaramaz.
jalopaba

9

Logrotate gibi bir araç bunu sizin için yapar. Günlük yönetimini çok kolaylaştırır. Ayrıca, halo'nun önerdiği gibi ek temizleme rutinleri de ekleyebilirsiniz.



1

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

1
Bu cevabı verdiğiniz için teşekkür ederiz. Bu gibi bir kod sağlamak yararlı olsa da, nasıl kullanılacağı veya kodun ne yaptığı hakkında bazı ek bilgiler sağlamanıza yardımcı olur. Gönderinizde daha sonra iyileştirmeler yapmak için düzenle düğmesini kullanabilirsiniz .
nhinkle

1

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.


1

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 {} \;


0

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"

0

Ayrıştırmanın kötü olduğu konusunda hemfikirim!

Sadece son 5 dosyanın /srv/backupsyolda kaldığından emin olun .

find /srv/backups -maxdepth 1 -type f -printf '%Ts\t%P\n' \
    | sort -rn \
    | tail -n +6 \
    | cut -f2- \
    | xargs -r r

0

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.