В bash-скрипте я хотел бы захватить стандартный вывод длинной командной строки за строкой, чтобы их можно было анализировать и сообщать, пока начальная команда еще выполняется. Это сложный способ сделать это:
# Start long command in a separated process and redirect stdout to temp file
longcommand > /tmp/tmp$$.out &
#loop until process completes
ps cax | grep longcommand > /dev/null
while [ $? -eq 0 ]
do
#capture the last lines in temp file and determine if there is new content to analyse
tail /tmp/tmp$$.out
# ...
sleep 1 s # sleep in order not to clog cpu
ps cax | grep longcommand > /dev/null
done
Я хотел бы знать, есть ли более простой способ сделать это.
РЕДАКТИРОВАТЬ:
Чтобы уточнить мой вопрос, я добавлю это. longcommand
Отображает его статус построчно один раз в секунду. Я хотел бы поймать вывод до longcommand
завершения.
Таким образом, я могу потенциально убить, longcommand
если он не даст ожидаемых результатов.
Я пытался:
longcommand |
while IFS= read -r line
do
whatever "$line"
done
Но whatever
(например echo
) выполняется только после longcommand
завершения.
Ответы:
Просто передайте команду в
while
цикл. Здесь есть ряд нюансов, но в основном (вbash
любой оболочке POSIX):Другой основной недостаток с этим (кроме
IFS
материала ниже) - это когда вы пытаетесь использовать переменные внутри цикла после его завершения. Это потому, что цикл на самом деле выполняется в под-оболочке (просто в другом процессе оболочки), к которой у вас нет доступа к переменным (также он завершается, когда цикл выполняется, и в этот момент переменные полностью исчезают. Чтобы обойти это, ты можешь сделать:Пример Hauke по настройке
lastpipe
вbash
другое решение.Обновить
Чтобы убедиться, что вы обрабатываете вывод команды «как это происходит», вы можете использовать
stdbuf
для установки процесса «stdout
буферизацию строки.Это настроит процесс для записи одной строки за раз в канал вместо внутренней буферизации его вывода в блоки. Помните, что программа может самостоятельно изменить эту настройку. Аналогичный эффект может быть достигнут с
unbuffer
(частьexpect
) илиscript
.stdbuf
доступно в системах GNU и FreeBSD, оно влияет только наstdio
буферизацию и работает только для приложений без setuid и setgid, которые динамически связаны (так как использует трюк LD_PRELOAD).источник
IFS=
не требуетсяbash
, я проверил это после последнего раза.line
(в этом случае результат вставляется$REPLY
без обрезки начальных и конечных пробелов). Попробуйте:echo ' x ' | bash -c 'read line; echo "[$line]"'
и сравните сecho ' x ' | bash -c 'IFS= read line; echo "[$line]"'
илиecho ' x ' | bash -c 'read; echo "[$REPLY]"'
источник