Принудительно сбрасывать вывод в файл, пока скрипт bash все еще работает - PullRequest
68 голосов
/ 16 сентября 2009

У меня есть небольшой скрипт, который ежедневно вызывается crontab с помощью следующей команды:

/homedir/MyScript &> some_log.log

Проблема с этим методом в том, что some_log.log создается только после завершения работы MyScript. Я хотел бы сбросить вывод программы в файл, пока он работает, чтобы я мог делать такие вещи, как

tail -f some_log.log

и отслеживать прогресс и т. Д.

Ответы [ 13 ]

64 голосов
/ 15 июня 2015

Я нашел решение для этого здесь . Используя пример ОП, вы в основном запускаете

stdbuf -oL /homedir/MyScript &> some_log.log

и затем буфер очищается после каждой строки вывода. Я часто комбинирую это с nohup для запуска длинных заданий на удаленной машине.

stdbuf -oL nohup /homedir/MyScript &> some_log.log

Таким образом, ваш процесс не отменяется при выходе из системы.

25 голосов
/ 16 сентября 2009

bash сам по себе никогда не запишет какой-либо вывод в ваш лог-файл. Вместо этого команды, которые он вызывает как часть сценария, будут по отдельности записывать выходные данные и сбрасываться всякий раз, когда им это нравится. Таким образом, ваш вопрос на самом деле заключается в том, как заставить команды в скрипте bash сбрасываться, и это зависит от того, что они собой представляют.

21 голосов
/ 31 января 2014

script -c <PROGRAM> -f OUTPUT.txt

Ключ -f. Цитата из сценария man:

 -f, --flush
         Flush output after each write.  This is nice for telecooperation: one person does `mkfifo foo; script -f foo', and another can supervise real-time what is being done
         using `cat foo'.

Запуск в фоновом режиме:

nohup script -c <PROGRAM> -f OUTPUT.txt
8 голосов
/ 13 апреля 2013

Вы можете использовать tee для записи в файл без необходимости очистки.

/homedir/MyScript 2>&1 | tee some_log.log > /dev/null
3 голосов
/ 16 сентября 2009

Это не функция bash, так как все, что делает оболочка, - это открывает рассматриваемый файл и затем передает дескриптор файла в качестве стандартного вывода сценария. Вам нужно убедиться, что вывод из вашего скрипта сбрасывается чаще, чем вы в настоящее время.

Например, в Perl это можно сделать, установив:

$| = 1;

См. perlvar для получения дополнительной информации об этом.

2 голосов
/ 09 апреля 2017

Буферизация вывода зависит от того, как реализована ваша программа /homedir/MyScript. Если вы обнаружите, что вывод буферизуется, вы должны принудительно применить его в своей реализации. Например, используйте sys.stdout.flush (), если это программа на Python, или используйте fflush (stdout), если это программа на C.

2 голосов
/ 23 декабря 2010

Поможет ли это?

tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq 

Это немедленно отобразит уникальные записи из access.log
http://www.pixelbeat.org/programming/stdio_buffering/stdbuf-man.html

1 голос
/ 07 июля 2018

Спасибо @user3258569, сценарий, пожалуй, единственное, что работает в busybox!

Но после этого снаряд замерз для меня. В поисках причины я обнаружил эти большие красные предупреждения "не использовать в неинтерактивных оболочках" на странице руководства script :

script в первую очередь предназначен для сеансов интерактивных терминалов. когда stdin не является терминалом (например: echo foo | script), тогда сеанс может зависнуть, потому что интерактивная оболочка внутри скрипта сессия пропускает EOF и script не имеет ни малейшего представления, когда закрывать сессию. См. NOTES раздел для получения дополнительной информации.

True. script -c "make_hay" -f /dev/null | grep "needle" замораживал скорлупу для меня.

В ответ на предупреждение, я думал, что echo "make_hay" | script ПРОЙДЕТ EOF, поэтому я попытался

echo "make_hay; exit" | script -f /dev/null | grep 'needle'

и это сработало!

Обратите внимание на предупреждения на странице руководства. Это может не сработать для вас.

1 голос
/ 26 июня 2014

Как только что заметил здесь проблема в том, что вам нужно ждать, пока программы, которые вы запускаете из своего скрипта, завершат свою работу.
Если в вашем скрипте вы запускаете программу в background , вы можете попробовать что-то еще.

Обычно вызов sync перед выходом позволяет очистить буферы файловой системы и может немного помочь.

Если в сценарии вы запускаете некоторые программы в background (&), вы можете дождаться, пока они завершат работу, прежде чем вы выйдете из сценария. Чтобы иметь представление о том, как он может функционировать, вы можете посмотреть ниже

#!/bin/bash
#... some stuffs ...
program_1 &          # here you start a program 1 in background
PID_PROGRAM_1=${!}   # here you remember its PID
#... some other stuffs ... 
program_2 &          # here you start a program 2 in background
wait ${!}            # You wait it finish not really useful here
#... some other stuffs ... 
daemon_1 &           # We will not wait it will finish
program_3 &          # here you start a program 1 in background
PID_PROGRAM_3=${!}   # here you remember its PID
#... last other stuffs ... 
sync
wait $PID_PROGRAM_1
wait $PID_PROGRAM_3  # program 2 is just ended
# ...

Поскольку wait работает с заданиями, а также с PID числами, ленивое решение должно быть помещено в конец скрипта

for job in `jobs -p`
do
   wait $job 
done

Более сложной является ситуация, если вы запускаете что-то, что запускает что-то другое в фоновом режиме, потому что вам нужно искать и ждать (если это так) завершения всего процесса child : например, если вы запустите daemon , вероятно, дело не в том, чтобы дождаться его завершения :-).

Примечание:

  • wait $ {!} Означает «дождаться завершения последнего фонового процесса», где $! - PID последнего фонового процесса. Таким образом, поставить wait ${!} сразу после program_2 & эквивалентно непосредственному выполнению program_2 без отправки его в фоновом режиме с &

  • С помощью wait:

    Syntax    
        wait [n ...]
    Key  
        n A process ID or a job specification
    
0 голосов
/ 25 января 2019

альтернатива stdbuf - awk '{print} END {fflush()}' Я бы хотел, чтобы для этого был встроенный bash. Обычно в этом нет необходимости, но в старых версиях могут быть ошибки синхронизации bash в файловых дескрипторах.

...