Bir günlük dosyasının yalnızca son n satırını nasıl saklarsınız?


18

Yazdığım bir senaryo bir şey yapar ve sonunda kendi günlük dosyasına bazı satırlar ekler. Günlük dosyasının yalnızca son n satırını (örneğin, 1000 satır) tutmak istiyorum. Bu, betiğin sonunda şu şekilde yapılabilir:

tail -n 1000 myscript.log > myscript.log.tmp
mv -f myscript.log.tmp myscript.log

ama daha temiz ve zarif bir çözüm var mı? Belki de tek bir komutla mı?


logrotatezarif bir çözümdür
Ipor Sircer

1
Bunu düşündüm, ancak logrotate konfigürasyonu betiğin kendisinden daha uzun olurdu ...
dr01

Eğer logrotat aşırıya kaçıyorsa, çözümünüz mümkün olduğu kadar zariftir. Sed / awk ile bir satırda yapabilir, ancak dahili bir geçici dosya olmadan yapamazsınız, bu yüzden muhtemelen daha verimli ve muhtemelen daha az okunabilir değildir.
kba Monica ile birlikte

Yanıtlar:


28

Bu mümkündür, ancak diğerlerinin söylediği gibi, en güvenli seçenek yeni bir dosyanın oluşturulması ve ardından orijinalin üzerine yazmak için bu dosyanın taşınmasıdır.

Aşağıdaki yöntem satırları BASH'e yükler, bu nedenle gelen satır sayısına bağlı olarak tail, günlük satırlarının içeriğini depolamak için yerel kabuğun bellek kullanımını etkiler.

Aşağıdakiler, günlük dosyasının sonunda (BASH değerlendirmesinin davranışı nedeniyle) boş satırları da kaldırır, bu "$(tail -1000 test.log)"nedenle tüm senaryolarda gerçekten% 100 doğru bir kesilme vermez, ancak durumunuza bağlı olarak yeterli olabilir.

$ wc -l myscript.log
475494 myscript.log

$ echo "$(tail -1000 myscript.log)" > myscript.log

$ wc -l myscript.log
1000 myscript.log

Akıllı. Ek araçların yüklenmesini gerektirmediği için bunu kabul edilen yanıt olarak işaretledim. Keşke seninkini ve @ John1024'ün cevabını kabul edebilseydim.
dr01

Çağrınız. Sünger çözümünü bilmiyordum ve boş günlük çizgileriyle uğraşmamak garanti. Bu çözüm, günlük dosyası içeriğine bağlı olarak bunu yapma potansiyeline sahiptir.
parkamark

Bu çözümün bir yarış durumu var. Şanssızsanız, -into- dosyasına yönlendirme dosyayı -from- dosyasını okumadan önce gerçekleşir ve sonunda boş bir dosya alırsınız.
Coroos

21

Yardımcı program spongesadece bu durum için tasarlanmıştır. Yüklediyseniz, iki satırınız yazılabilir:

tail -n 1000 myscript.log | sponge myscript.log

Normalde, bir dosyaya yazarken aynı anda dosyadan okumak güvenilir değildir. bunu, okumayı bitirip boruyu sonlandırana kadar spongeyazmadan çözer .myscript.logtail

Yüklemek

spongeDebian benzeri bir sisteme kurmak için:

apt-get install moreutils

spongeBir RHEL / CentOS sistemine kurmak için EPEL deposunu ekleyin ve ardından şunları yapın:

yum install moreutils

belgeleme

Gönderen man sponge:

spongestandart girdiyi okur ve belirtilen dosyaya yazar. Bir kabuk yönlendirmesinin aksine sponge, çıktı dosyasını yazmadan önce tüm girdilerini emer. Bu, aynı dosyadan okunan ve aynı dosyaya yazılan boru hatlarının oluşturulmasına izin verir.


2
+1 Teşekkürler, bilmiyordum sponge. sort importantfile.txt > importantfile.txt
Yapamayacağınız

4

kesinlikle "kuyruk + mv" çok daha iyi! Ama gnu sed için deneyebiliriz

sed -i -e :a -e '$q;N;101,$D;ba' log

3

Kayıt için, edsenin gibi bir şey yapabilirdin

ed -s infile <<\IN
0r !tail -n 1000 infile
+1,$d
,p
q
IN

Bu , çıktısını açar infileve açar (yani, bu çıktıyı 1. satırdan önce ekler) ve sonra başlangıçta 1. satırdan dosyanın sonuna kadar siler. Yerinde dosyayı düzenlemek için ile değiştirin . Ancak, çözümlerin büyük dosyalar için uygun olmadığını unutmayın .rtail -n 1000 infile,pw
ed


0

Senaryonuzda yapabileceğiniz şey, günlük dönüş mantığını uygulamaktır. Tüm günlük kaydını bir işlevle yapın:

log()
{
   ...
}

Bu işlev, öncelikle, şöyle bir şey yapar:

printf "%s\n" "$*" >> logfile

daha sonra, dosyanın boyutunu kontrol eder veya bir şekilde dosyanın döndürülmesi gerektiğine karar verir. Bu noktada, logfile.1varsa dosya kaldırılır logfile.0, varsa dosya olarak yeniden adlandırılır logfile.1ve logfileyeniden adlandırılır logfile.0.

Döndürülüp döndürülmeyeceğine karar vermek, betiğin kendisinde tutulan bir sayacı temel alabilir. 1000'e ulaştığında sıfıra sıfırlanır.

Her zaman 1000 satıra kesinlikle düzeltme yapmak bir zorunluluksa, komut dosyası başlatıldığında günlük dosyasındaki satır sayısını sayabilir ve sayacı buna göre başlatabilir (veya sayım zaten 1000'i karşılar veya aşıyorsa, hemen döndürmeyi yapın).

Ya da boyutu ile elde edebilir wc -c logfileve belirli bir boyutu aşmaya dayalı olarak dönüş yapabilirsiniz. Bu şekilde, koşulu belirlemek için dosyanın hiçbir zaman taranması gerekmez.


0

Bunun yerine, bir Yazılımın çalıştığı yerde bazı günlük dosyalarına sahip olabileceğinizi başarmak mviçin cpkomutu kullandım. Belki farklı Kullanıcı ana dizininde veya uygulama dizininde ve tüm günlükleri sabit olarak tek bir yerde bulundurun. mvKomutu kullanırsanız sabit bağlantıyı kaybedersiniz. Eğer kullanırsanız cpkomutu yerine bu sert linki tutacak.

kodum gibi bir şey:

TMP_FILE="$(mktemp "${TMPFILENAME}.XXX")"

for FILE in "${LOGFILE_DIR}"/* ; do
    tail -n $MAXLINES "${FILE}" > "${TMP_FILE}"
    if [ $(ls -g "${TMP_FILE}" | awk '{print $4}') -lt $(ls -g "${FILE}" | awk '{print $4}') ] ; then
        cp "${TMP_FILE}" "${FILE}"
    fi
done   

Bu yüzden dosyalar aynı Dosya Sistemindeyse, kullanıcılara bazı farklı haklar verebilirsiniz ve ${LOGFILE_DIR}siz de benim yaptığım gibi uzunluğu değiştirebilirsiniz.

mvKomut buysa , dosyalar arasındaki bağlantıyı kaybedersiniz ve böylece ikinci dosyanız birincisine daha fazla bağlı değildir - belki başka bir yere yerleştirilmiş olabilir.

Diğer yerde, birinin dosyayı silmesine izin vermezseniz, günlükleriniz bir arada kalır ve kendi komut dosyanızla iyi kontrol edilir.

logrotatebelki daha güzel. Ama bu çözümden memnunum.

Rahatsız etmeyin "" ama benim durumumda boşluklar ve diğer özel harfler içeren bazı dosyalar var ve "" yapmazsam ya da {} tüm işler iyi çalışmaz.

Örneğin, eski dosyaların otomatik olarak sıkıştırılmış olduğu bir Dir vardır OLDFILE.zipve sıkıştırılmış olan her şey Dosya'da da listelenir, .zip_logbu yüzden .zip_logbu Dir'de de var ama LOGFILE_DIRbende var:

ln .zip_log "${LOGFILE_DIR}/USER_ZIP_log"

sabit bir bağlantı olduğu için eşit dosya.

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.