Linux tee komutu, aldığı uygulamayı öldürmeden nasıl sonlandırılır


19

Linux makinesi açık olduğu sürece çalışan bir bash betiğim var. Aşağıda gösterildiği gibi başlatırım:

( /mnt/apps/start.sh 2>&1 | tee /tmp/nginx/debug_log.log ) &

Lauches sonra, aşağıda gösterildiği gibi benim ps çıkış tee komut görebilirsiniz :

$ ps | grep tee
  418 root       0:02 tee /tmp/nginx/debug_log.log
3557 root       0:00 grep tee

Tee belirli bir boyuta ulaştığında tee üreten ve tee komutunu öldüren günlük boyutunu izleyen bir işlevi var :

monitor_debug_log_size() {
                ## Monitor the file size of the debug log to make sure it does not get too big
                while true; do
                                cecho r "CHECKING DEBUG LOG SIZE... "
                                debugLogSizeBytes=$(stat -c%s "/tmp/nginx/debug_log.log")
                                cecho r "DEBUG LOG SIZE: $debugLogSizeBytes"
                                if [ $((debugLogSizeBytes)) -gt 100000 ]; then
                                                cecho r "DEBUG LOG HAS GROWN TO LARGE... "
                                                sleep 3
                                                #rm -rf /tmp/nginx/debug_log.log 1>/dev/null 2>/dev/null
                                                kill -9 `pgrep -f tee`
                                fi
                                sleep 30
                done
}

Şaşırtıcı bir şekilde , tee komutunu öldürmek de start.sh örneğiyle öldürür. Bu neden? Tee komutunu nasıl sonlandırabilirim ama start.sh dosyam çalışmaya devam edebilir? Teşekkürler.

Yanıtlar:


34

Ne zaman teeson bulur, daha çıktı yazma girişiminde kadar, çalışmaya devam edecek besleme komutu. Daha sonra okuyucu olmadan bir boruya yazmaya çalışmak için bir SIGPIPE (çoğu sistemde 13) alacaktır.

Komut dosyanızı SIGPIPE'i yakalamak ve bazı uygun eylemleri (çıktı yazmayı durdurmak gibi) yapacak şekilde değiştirirseniz, tee sonlandırıldıktan sonra da devam etmesini sağlayabilirsiniz.


Daha da iyisi, öldürmek yerine tee , basitlik seçeneği logrotateile kullanın copytruncate.

Alıntı yapmak için logrotate(8):

copytruncate

Bir kopya oluşturduktan sonra eski günlük dosyasını taşımak ve isteğe bağlı olarak yeni bir dosya oluşturmak yerine orijinal günlük dosyasını yerinde kesin. Bazı programların günlük dosyalarını kapatması söylenemediğinde kullanılabilir ve böylece önceki günlük dosyasına sonsuza kadar yazmaya (eklenerek) devam edebilir. Dosyayı kopyalayıp kısaltmak arasında çok küçük bir zaman dilimi olduğunu unutmayın, bu nedenle bazı günlük verileri kaybolabilir. Bu seçenek kullanıldığında, eski günlük dosyası yerinde kaldığından oluşturma seçeneğinin bir etkisi olmaz.


9
Ayrıca dosyayı ekleme modunda açmak tee -aiçin de kullanmak istersiniz tee, aksi takdirde tee, dosyayı kestikten sonra aynı ofsette (ve macOS'taki gibi seyrek dosyaları desteklemeyen sistemlerde yazmaya devam eder) dosyanın bu konuma giden bölümünü iki kat daha fazla disk alanı kaplar).
Stéphane Chazelas

4
Diğer seçenek, logger -ssistem günlüğü ile ilgilenmek için syslog'a yöneltmek olacaktır ( -sayrıca stderr'a yazdırmak için).
Stéphane Chazelas

1
İçin +1 logrotate. Büyük program
Dmitry Kudriavtsev

2
Veya systemd ve dergi kullanan bir sistemde, logger yerine systemd-cat. Sonra ücretsiz olarak çok sayıda çıktı filtreleme ve döndürme elde edersiniz.
Zan Lynx

3

"Neden" in açıklaması

Kısacası: Yazma başarısız olursa bir programın çıkmasına neden olmazsa (varsayılan olarak), bir karışıklık olur. Düşünün find . | head -n 10- ihtiyaç duyduğunuz ve devam eden 10 satırı findaldıktan sonra head, sabit sürücünüzün geri kalanını taramaya devam etmek istemezsiniz .

Daha İyi Yapmak: Kaydedicinizin İçinde Döndürün

teeGösterici bir örnek olarak hiç kullanmayan aşağıdakileri düşünün :

#!/usr/bin/env bash

file=${1:-debug.log}                     # filename as 1st argument
max_size=${2:-100000}                    # max size as 2nd argument
size=$(stat --format=%s -- "$file") || exit  # Use GNU stat to retrieve size
exec >>"$file"                           # Open file for append

while IFS= read -r line; do              # read a line from stdin
  size=$(( size + ${#line} + 1 ))        # add line's length + 1 to our counter
  if (( size > max_size )); then         # and if it exceeds our maximum...
    mv -- "$file" "$file.old"            # ...rename the file away...
    exec >"$file"                        # ...and reopen a new file as stdout
    size=0                               # ...resetting our size counter
  fi
  printf '%s\n' "$line"                  # regardless, append to our current stdout
done

Şu şekilde çalıştır:

/mnt/apps/start.sh 2>&1 | above-script /tmp/nginx/debug_log

... bu, 100KB'den fazla içerik bulunduğunda /tmp/nginx/debug_logdosyanın adını değiştirerek başlayacak /tmp/nginx/debug_log.old. Kaydedicinin kendisi dönüşü gerçekleştirdiği için, döndürme gerçekleştiğinde kırık bir boru, hata ve veri kaybı penceresi yoktur - her satır bir dosyaya veya diğerine yazılır.

Tabii ki, bunu doğal bash'da uygulamak verimsizdir, ancak yukarıdakiler açıklayıcı bir örnektir. Yukarıdaki mantığı sizin için uygulayacak çok sayıda program vardır. Düşünmek:

  • svlogd, Runit paketindeki hizmet günlüğü.
  • s6-log, skanet süitinden aktif olarak korunan bir alternatif.
  • multilog DJB Daemontools, bu süreç denetleme ve izleme araç ailesinin büyükbabası.
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.