GNU/Linux >> Belajar Linux >  >> Linux

pengalihan keluaran on-the-fly, melihat keluaran pengalihan file saat program masih berjalan

Dari stdout halaman manual:

Stream stderr tidak di-buffer. Stream stdout di-buffer garisketika menunjuk ke terminal .Partial lines tidak akan muncul hinggafflush(3) atau exit(3) dipanggil, atau baris baru dicetak.

Intinya:Kecuali outputnya adalah terminal, program Anda akan memiliki output standarnya dalam mode buffer penuh secara default. Ini pada dasarnya berarti bahwa itu akan menampilkan data dalam blok besar, bukan baris demi baris, apalagi karakter demi karakter.

Cara untuk mengatasinya:

  • Perbaiki program Anda:Jika Anda memerlukan keluaran waktu nyata, Anda perlu memperbaiki program Anda. Di C Anda dapat menggunakan fflush(stdout) setelah setiap pernyataan output, atau setvbuf() untuk mengubah mode buffering dari keluaran standar. Untuk Python ada sys.stdout.flush() bahkan beberapa saran di sini.

  • Gunakan utilitas yang dapat merekam dari PTY, daripada pengalihan stdout langsung. Layar GNU dapat melakukannya untuk Anda:

    screen -d -m -L python test.py
    

    akan menjadi awal. Ini akan mencatat output program Anda ke file bernama screenlog.0 (atau serupa) di direktori Anda saat ini dengan penundaan default 10 detik, dan Anda dapat menggunakan screen untuk terhubung ke sesi tempat perintah Anda berjalan untuk memberikan input atau menghentikannya. Penundaan dan nama file log dapat diubah dalam file konfigurasi atau secara manual setelah Anda tersambung ke sesi latar belakang.

EDIT:

Pada sebagian besar sistem Linux, ada solusi ketiga:Anda dapat menggunakan LD_PRELOAD variabel dan pustaka yang dimuat sebelumnya untuk mengganti fungsi tertentu dari pustaka C dan menggunakannya untuk menyetel stdout mode buffering saat fungsi tersebut dipanggil oleh program Anda. Metode ini mungkin berhasil, tetapi memiliki beberapa kelemahan:

  • Itu tidak akan bekerja sama sekali pada executable statis

  • Itu rapuh dan agak jelek.

  • Itu tidak akan berfungsi sama sekali dengan SUID yang dapat dieksekusi - pemuat dinamis akan menolak untuk membaca LD_PRELOAD variabel saat memuat executable tersebut untuk alasan keamanan.

  • Itu rapuh dan agak jelek.

  • Ini mengharuskan Anda menemukan dan mengganti fungsi pustaka yang dipanggil oleh program Anda setelah awalnya menyetel stdout mode buffering dan sebaiknya sebelum keluaran apapun. getenv() adalah pilihan yang baik untuk banyak program, tetapi tidak semua. Anda mungkin harus mengganti fungsi I/O umum seperti printf() atau fwrite() - jika push datang untuk mendorong Anda mungkin hanya perlu mengesampingkan semua fungsi yang mengontrol mode buffering dan memperkenalkan kondisi khusus untuk stdout .

  • Itu rapuh dan agak jelek.

  • Sulit untuk memastikan bahwa tidak ada efek samping yang tidak diinginkan. Untuk melakukannya dengan benar, Anda harus memastikan bahwa hanya stdout terpengaruh dan penggantian Anda tidak akan merusak sisa program jika mis. stdout ditutup.

  • Apakah saya menyebutkan bahwa itu rapuh dan agak jelek?

Konon, prosesnya relatif sederhana. Anda memasukkan file C, mis. linebufferedstdout.c fungsi pengganti:

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>


char *getenv(const char *s) {
    static char *(*getenv_real)(const char *s) = NULL;

    if (getenv_real == NULL) {
        getenv_real = dlsym(RTLD_NEXT, "getenv");

        setlinebuf(stdout);
    }

    return getenv_real(s);
}

Kemudian Anda mengompilasi file itu sebagai objek bersama:

gcc -O2 -o linebufferedstdout.so -fpic -shared linebufferedstdout.c -ldl -lc

Kemudian Anda mengatur LD_PRELOAD variabel untuk memuatnya bersama dengan program Anda:

$ LD_PRELOAD=./linebufferedstdout.so python test.py | tee -a test.out 
0
1000
2000
3000
4000

Jika Anda beruntung, masalah Anda akan terselesaikan tanpa malang efek samping.

Anda dapat mengatur LD_PRELOAD perpustakaan di shell, jika perlu, atau bahkan tentukan perpustakaan itu di seluruh sistem (pasti BUKAN direkomendasikan) di /etc/ld.so.preload .


Sudahkah Anda mempertimbangkan untuk melakukan piping to tee?

./program | tee a.txt

Namun, bahkan tee tidak akan berfungsi jika "program" tidak menulis apa pun ke stdout hingga selesai. Jadi, keefektifannya sangat bergantung pada bagaimana perilaku program Anda.


Jika Anda mencoba mengubah perilaku program yang ada, coba stdbuf (bagian dari coreutils yang dimulai dengan versi 7.5).

Ini buffer stdout hingga baris:

stdbuf -oL command > output

Ini menonaktifkan buffering stdout sama sekali:

stdbuf -o0 command > output


Linux
  1. Baca dan tulis data dari mana saja dengan pengalihan di terminal Linux

  2. Cara Mengarahkan Output ke File dan Stdout di Linux

  3. Bagaimana Mengubah Pengalihan Output Dari Proses yang Berjalan?

  1. Menutup Output Standar (>&-)?

  2. Pengalihan Io Dan Perintah Kepala?

  3. Cara mengarahkan output ke file dan stdout

  1. menampilkan kolom ke-2 dari sebuah file

  2. Redirect semua output ke file di Bash

  3. Bagaimana cara mengarahkan output dari system() ke file?