Силовая промывка вывода в файл, пока bash script все еще работает
У меня есть небольшой script, который ежедневно вызывается crontab, используя следующую команду:
/homedir/MyScript &> some_log.log
Проблема с этим методом заключается в том, что some_log.log создается только после завершения MyScript. Я хотел бы очистить вывод программы в файл во время работы, чтобы я мог делать что-то вроде
tail -f some_log.log
и отслеживать прогресс и т.д.
Ответы
Ответ 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.