Подтвердить что ты не робот

Силовая промывка вывода в файл, пока bash script все еще работает

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

/homedir/MyScript &> some_log.log

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

tail -f some_log.log

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

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

Ответ 3

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

Ответ 4

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

/homedir/MyScript 2>&1 | tee some_log.log > /dev/null

Ответ 5

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

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

$| = 1;

Подробнее см. perlvar.

Ответ 6

Это поможет?

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

Это немедленно отобразит уникальные записи из access.log с помощью утилиты stdbuf.

Ответ 7

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

Ответ 8

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

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

Если в script вы запускаете некоторые программы в фон (&), вы можете wait, которые они заканчивают перед выходом из script. Чтобы иметь представление о том, как он может функционировать, вы можете увидеть ниже

#!/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, то ленивым решением должно быть положить конец script

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
    

Ответ 9

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

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

script в первую очередь предназначен для интерактивных сеансов терминала. Когда stdin не является терминалом (например: echo foo | script), тогда сеанс может зависать, потому что интерактивная оболочка в сеансе скрипта пропускает EOF, и script не имеет понятия, когда нужно закрыть сеанс. Дополнительную информацию см. В разделе ПРИМЕЧАНИЯ.

Правда. script -c "make_hay" -f/dev/null | grep "needle" script -c "make_hay" -f/dev/null | grep "needle" замерла для меня.

В отличие от предупреждения, я думал, что echo "make_hay" | script echo "make_hay" | script будет проходить EOF, поэтому я попробовал

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

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

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

Ответ 10

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

Ответ 11

Я не знаю, будет ли это работать, но как насчет вызова sync?

Ответ 12

У меня была эта проблема с фоновым процессом в Mac OS X с помощью StartupItems. Вот как я его решаю:

Если я создаю sudo ps aux, я вижу, что запускается mytool.

Я обнаружил, что (из-за буферизации), когда Mac OS X выключается, mytool никогда не передает вывод команде sed. Однако, если я выполняю sudo killall mytool, то mytool переносит вывод в команду sed. Следовательно, я добавил случай stop в StartupItems, который выполняется, когда Mac OS X выключается:

start)
    if [ -x /sw/sbin/mytool ]; then
      # run the daemon
      ConsoleMessage "Starting mytool"
      (mytool | sed .... >> myfile.txt) & 
    fi
    ;;
stop)
    ConsoleMessage "Killing mytool"
    killall mytool
    ;;

Ответ 13

хорошо нравится это или нет, так работает перенаправление.

В вашем случае вывод (то есть ваш script завершен) вашего script перенаправлен на этот файл.

Что вы хотите сделать, это добавить эти перенаправления в script.