2015-06-22 7 views
1

Я хочу скопировать stdout в файл журнала с в пределах сценарий bash, то есть я не хочу вызывать скрипт с выходом, переданным в tee, я хочу сам сценарий для его обработки. Я успешно использовал this ответ для достижения этой цели, используя следующий код:Копировать * небуферизованный * stdout для файла из самого скрипта bash

#!/bin/bash 
exec > >(sed "s/^/[${1}] /" | tee -a myscript.log) 
exec 2>&1 

# <rest of script> 
echo "hello" 
sleep 10 
echo "world" 

Это работает, но имеет недостаток выхода буферизации, пока сценарий не будет завершен, а также обсуждается в связанном ответ. В приведенном выше примере как «привет», так и «мир» будут отображаться в журнале только после того, как пройдут 10 секунд.

Я знаю команду stdbuf, и если запустить скрипт с

stdbuf -oL ./myscript.sh 

то стандартный вывод действительно непрерывно печатается как в файл и терминалом. Однако мне бы хотелось, чтобы это было обработано и внутри скрипта. Есть ли способ объединить эти два решения? Я бы предпочел не прибегать к сценарию обертки, который просто вызывает исходный скрипт, заключенный в «stdbuf -oL».

ответ

0

Вы можете использовать обходной путь и сделать сценарий выполнения себя stdbuf, если специальный аргумент присутствует:

#!/bin/bash 

if [[ "$1" != __BUFFERED__ ]]; then 
    prog="$0" 
    stdbuf -oL "$prog" __BUFFERED__ "[email protected]" 
else 
    shift #discard __BUFFERED__ 

    exec > >(sed "s/^/[${1}] /" | tee -a myscript.log) 
    exec 2>&1 

    # <rest of script> 
    echo "hello" 
    sleep 1 
    echo "world" 
fi 

Это будет в основном работать:

  • , если вы запустите скрипт с ./test , он показывает небуферизованный [] hello\n[] world.
  • если вы запустите скрипт с ./test 123 456, он отобразит [123] hello\n[123] world, как вы хотите.
  • он не будет работать, однако, если вы запустите его с bash test - $0 установлен в test, который не является вашим скриптом. Однако это не входит в сферу применения этого вопроса.
+0

Спасибо. Эти ограничения действительно в порядке. Тбх, возможно, это не самое чистое решение :-), но я попробую. – JHH

0

Задержка в вашем первом решении вызвана sed, а не tee. Попробуйте вместо этого:

#!/bin/bash 
exec 6>&1 2>&1>&>(tee -a myscript.log) 

"отменить" в tee эффект:

exec 1>&6 2>&6 6>&- 
+0

Спасибо. Вы уверены, что в этом случае? Довольно точно то же самое произошло без sed, но я дважды проверю. Кроме того, не могли бы вы объяснить, что делает ваше предложение, что с 6? – JHH

+0

Я столкнулся с проблемой [аналогичного] (http://stackoverflow.com/questions/30786082/convert-expect-output-from-dos-to-unix-style-in-realtime) (не полностью подключенной к вам сначала), в котором я пытался «dos2unix» выводить определенный процесс, связывая его stdout с sed/perl/tr/dos2unix/etc и дублируя его с помощью 'tee' одновременно. Я не мог избавиться от раздражающего эффекта задержки/буферизации, когда оба включены. В конце концов я решил только «tee' *» и позже выполнить «dos2unix». Дополнительная информация о перенаправлении stdout/stderr на fd6 [здесь] (http://www.tldp.org/LDP/abs/html/x17974.html) –