LINUX.ORG.RU
ФорумAdmin

кошмар в стиле bash


0

0

Привет. У меня есть такая задача:

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

# логфайл
MFLOG=/home/ierton/store/tmp/mailfly.log
# сам скрипт. Питоновый, что характерно.
MAILFLY=`dirname $0`/mailfly.py

# Запускаю скрипт, добавляю время, пишу в файл.
/usr/bin/python "$MAILFLY" 2>&1 | awk ' { printf("%s: %s\n", strftime(), $0); } ' | tee $MFLOG

Только вот зараза не работает. Файл пустой получается. А если так:
/usr/bin/python "$MAILFLY" >> $MFLOG 2>&1
то все отлично. В чем тут дело, кто видит?

★★

Ответ на: комментарий от sin_a

> У меня дежавю...

Надо было синюю брать!

ierton ★★
() автор топика
Ответ на: комментарий от marsijanin

> Вообще ещё можно из самого awk'a в файл писать.

На связке awk '...' | tee logfile.log какраз все нормально.
Такое впечатление, что пайп из питоновского скрипта не работает.
В самом скрипте для вываода используется print`ы типа:

print "Processing message %s" % id
caller, url = poller.fetchMailSubject(id)
print "From: %s" % caller
print "Link: %s" % url

А если исключение падает - то уже сам питон в свой поток ошибок пишет.

ierton ★★
() автор топика

а если скрипт что-то пишет в файл и нормально завершает работу, то файл тоже остаётся пустым?

Если да - то не знаю: питона не знаю, твоего скрипта у меня тоже нет, а с перлом всё нормально получается:

$perl -e "print 'hello';" |awk ' { printf("%s: %s\n", strftime(), $0); } ' | tee /tmp/aa
$ cat /tmp/aa
Втр Мар 11 02:00:20 MSK 2008: hello

Если нет - то, видимо, дело в буферизации (man fflush, man setbuf), сравни поведение:

(echo hello; sleep 1) |tee
(echo hello; sleep 1) |awk ' { printf("%s: %s\n", strftime(), $0); } '
(echo hello; sleep 1) |awk ' { printf("%s: %s\n", strftime(), $0); fflush(); } ' |tee
и
(echo hello; sleep 1) |awk ' { printf("%s: %s\n", strftime(), $0); } ' |tee

И попробуй то же самое не с (echo hello; sleep 1), а с питоном - скорее всего, он буферизует stdout. Если так, то заботай, как выключить буферизацию или сделать в питоне flush().

alexsaa
()

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

Deleted
()
Ответ на: комментарий от Deleted

Заменил в баш-скрипте awk на sed, чтобы исключить его.

/usr/bin/python $MFDIR/testout.py 2>&1 | sed "s/\(.*\)/`date`: \1/g" | tee -a $MFLOG

тестовый питон-скрипт такой


while True:
print "I am working"
sys.stdout.flush()
sleep(1)


Работает следующим образом: молчит секунд 5, потом вываливает сразу кучу "I am working" (обрывая последнюю на полуслове). Дело и правда гдето в буферизации питона. Спасибо, Ботаю)

ierton ★★
() автор топика
Ответ на: комментарий от ierton

Не, не так просто всеже. Если вообще убрать sed (awk)

/usr/bin/python $MFDIR/testout.py 2>&1 | tee -a $MFLOG

то все будет ништяк с темеже скриптами.
Может ли быть проблема в буфере самого башевского пайпа?

ierton ★★
() автор топика
Ответ на: комментарий от ierton

Ты ж, вроде, уже сделал flush() в скрипте, что ещё там ковырять? :)

Потом, думаешь, замена awk на sed выключит буферизацию? Её надо выключать (или делать flush) явно ;) Пример flush() для awk я уже привёл. В man sed читай про -u, см. пример ниже.

смотри, вроде всё работает? python testout.py | sed -u "s/\(.*\)/`date`: \1/g" |tee

alexsaa
()
Ответ на: комментарий от ierton

> Может ли быть проблема в буфере самого башевского пайпа?

Баш просто создаёт пайп. У пайпа, конечно, есть какая-то максимальная длина буфера, но намеренно скрывать от одного процесса данные, записанные туда другим процессом, он не станет. Зато вот записью данных в пайп со стороны питона, awk'а, sed'а и пр. занимается libc. А к ней в полной мере применимы man setbuf. И по умолчанию потоки имеют некоторую буферизацию. Её-то и надо выключать - средствами каждой конкретной программы - каждый раз, когда её stdout перенаправляешь во что-то, отличное от консоли. Вот и все премудрости.

Для этого *достаточно* сделать flush() в скрипте (кстати. как вариант - выводить через stderr, у которого по умолчанию буферизация выключена) *И* выключить буфер либо сделать авто-flush в твоём фильтре (как я понимаю, awk: flush, sed: -u). У tee во всех *моих* примерах делать flush не нужно, т.к. я его вывод не перенаправлял. Возможно, для записи в файл (-a) понадобится ещё что-то (man tee).

alexsaa
()
Ответ на: комментарий от alexsaa

Ах, ёлыпалы:) -u работает. И flush() работает, незнаю чем я пробовал первый раз.. А ещё работает такой изврат :

$MFDIR/testout.py 2>&1 | bash -c "while true; do read A; date | tr -d '\n'; echo ': '\$A; done" | tee -a $MFLOG

Спасибо!

ierton ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.