Son dosyada 50 satır sonunu nasıl tutar?


21

Dosyamda son 50 satırı tutmaya çalışıyorum, burada her dakika sıcaklıktan tasarruf ediyorum. Bu komutu kullandım:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test

Ancak sonuç boş sınama dosyasıdır. Son 50 satırlık test dosyasını listeler ve test dosyasına ekler diye düşündüm. Bu komutu kullandığımda:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test2

iyi çalışıyor. Test2 dosyasında 50 satır var.

Birisi bana sorunun nerede olduğunu açıklayabilir mi?


2
Rrdtool gibi bir şey zaman içinde N kayıtlarını tutmak için daha uygun olabilir (diğer istatistikler arasında).
thrig


2
klasik truncation sorunu
haylem

Günlüklerinizi oluşturmak için python kullanıyorsanız, loggingmodülün içine bakmalısınız
Wayne Werner

Yanıtlar:


29

Sorun şu ki, kabuğunuz komutları çalıştırmadan önce komut satırını ayarlıyor. Bu, "giriş ve çıkış" meselesi değil, dosyanın içeriği kuyruk çalışmadan önce zaten gider. Gibi bir şey gider:

  1. Kabuk, >çıktı dosyasını yazmak için açar , keser
  2. Kabuk, dosya çıktısının 1 (stdout için) bu çıktı için kullanılmasını sağlar.
  3. Kabuk yürütür tail.
  4. tailorada koşar, açar /home/pi/Documents/testve hiçbir şey bulamaz

Çeşitli çözümler var, ancak asıl sorun sorunu, gerçekte neyin yanlış gittiğini ve nedenini anlamak.

Bu aradığınızı üretecek,

echo "$(tail -n 50 /home/pi/Documents/test)" > /home/pi/Documents/test

Açıklama:

  • $() yürüten komut yerine koyma denir tail -n 50 /home/pi/Documents/test
  • tırnak işaretleri çıktıdaki satır kesmelerini korur.
  • > /home/pi/Documents/testçıktısını echo "$(tail -n 50 /home/pi/Documents/test)"aynı dosyaya yönlendirir .

Teşekkürler iyi çalışıyor! Bir sorum daha var. Lütfen prosedürünüzün adım adım nasıl çalıştığını açıklayabilir misiniz?
dorinand

1
Fakat neden sizin durumunuzda bash> ilk önce yapmıyor? Bash'in emri nasıl ilerlediğini anlamıyorum. Herhangi biri açıklayabilir mi?
dorinand

1
> Echo komutundadır, bu nedenle echo komutu yürütmeye başladığında çalıştırılır. Yazılmadan önce yürütmeye başlayamaz. Değişken ikame, komutu yazan şeydir. Nested komutunu çalıştırır ve değerde değiştirerek echo komutunu oluşturur.
jobermark

Aynısını 44gb günlük dosyası için 50 yerine 5000 satır kullanarak kullanmaya çalıştığımda hata alıyorumbash: xrealloc: cannot allocate 18446744071562067968 bytes
Carmageddon

8

Dosya yeniden yönlendirmesine ilk önce dosyayı temizleyen başka bir çözüm spongede moreutilspaketten şu şekilde kullanmaktır :

tail -n 50 /home/pi/Documents/test | sponge /home/pi/Documents/test

6

Bunun nedeni, bash >dosyasının içeriğini silerek ilk yönlendirmeyi işlemesidir . Sonra komutu yürütür. Kullanmanız halinde >>, son 50 satır, dosyada bulunanların sonuna eklenir. Bu durumda, aynı 50 çizgiyi iki kez tekrarlamanız gerekir.

Komut, farklı bir dosyaya yönlendirirken beklendiği gibi çalışır. Dosyanın son 50 satırını aynı ada sahip bir dosyaya yazmanın bir yolu:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 && mv /home/pi/Documents/test2 /home/pi/Documents/test

Bu ilk önce son 50 satırı geçici bir dosyaya yazar ve bu mvdosya orijinal dosyayı değiştirmek için kullanılır .

Yorumlarda belirtildiği gibi, dosya hala açıksa bu işe yaramaz. Dosyanın taşınması da yeni bir inode oluşturur ve sahiplik ve izinleri değiştirebilir. Geçici bir dosya kullanarak bunu yapmanın daha iyi bir yolu olacaktır:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 ; cat /home/pi/Documents/test2 > /home/pi/Documents/test

Geçici dosya da kaldırılabilir, ancak bu her gerçekleştiğinde içeriğinin üzerine yazılacaktır.


teşekkür ederim. Bana bash'ın ne yaptığını adım adım açıklar mısınız? Nasıl çalıştığını hayal edemiyorum.
dorinand

tail -50 /home/pi/Documents/test >/tmp/foo && cat /tmp/foo >/home/pi/Documents/test
steve

1
Günlük dosyası hala kayıt işlemi tarafından açıksa (bu işlem orijinal, silinmiş dosyaya giriş yapmaya devam edecektir) çalışmaz. tempfile + move, yeni bir inode (hard linkleri kırarak) ve muhtemelen farklı sahip veya izinlerle sonuçlanır. tail ... > temp ; cat temp > orig ; rm -f tempEserleri.
cas,

4

Ana sorunu kabuk yönlendirme ile gördüğünüzden beri, bir dosyayı son 50 satırına budamak için alternatif bir yol:

file=/path/to/the/file
n=$(( $(wc -l < "$file") - 50 ))
[[ $n -gt 0 ]] && sed -i 1,${n}d "$file"

Zor iş (GNU) -içıktıyı geçici bir dosyada oluşturarak kapakların altında çalışan "yerinde düzenleme" özelliği ile baştan sona yapılır . Satırların geri kalanı sed'i işletmek için matematiği, yani:

  1. dosyadaki ( wc) satırları sayın , sonra 50'yi çıkarın; bunu ona ver n.
  2. eğer n pozitif ise, n içinden silme hatlar 1 sed komutunu çalıştırın.

4
printf '%s\n' '1,$-50d'   w | ed -s /home/pi/Documents/tes

printfkomutları (her satıra bir tane) iletmek için kullanılır ed. edKomutlar şunlardır:

  • 1,$-50d - Son 50 satırdan sonra tümünü sil
  • w - değiştirilen dosyayı diske geri yaz

Yeniden yönlendirmeler yoktur, bu nedenle kabuk okunmadan önce çıktı dosyasının üzerine yazamaz.

Ayrıca, çoğu "yerinde" düzenleme biçimlerinin aksine (genellikle "yerinde" düzenlemeyi geçici bir dosya oluşturarak ve ardından orijinalin üzerinde yeniden adlandırarak yalnızca "simüle eder"), edaslında orijinal dosyayı düzenler - böylece aynı inode'u tutar ( ve sahibi, grup ve izinleri - tempfile + mv olacak hep düğüm değiştirmek ve olabilecek koşullara bağlı olarak diğerlerini) değiştirin.


4

Biraz farklı bir parçada, logrotate(8)günlük dosyalarını düzenli aralıklarla adlandırılmış dosyaları yedeklemek için düzenli olarak yedekleyebilir ve ardından eski dosyaları silebilirsiniz.

Ana sistem günlük dosyalarının çok uzun süre büyümelerini engellemek için yönetilmeleri budur.

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.