Скрыть стандартный вывод процесса, только если он запущен в фоновом режиме
Как я могу скрыть стандартный вывод процесса, только когда он выполняется в фоновом режиме?
Например,
test.sh
#!/bin/bash
for i in $(seq 200); do
echo $i
done
Теперь я запускаю скрипт. Я прекращаю это. Я положил его обратно, чтобы проверить, что он продолжает работать. Затем я положил его на фон, но он продолжает печатать со стандартным выводом, и я не могу продолжать работать. Есть ли способ перенаправить или скрыть вывод процесса ТОЛЬКО в фоновом режиме?
dione@saturno:~$ ./test.sh
1
2
3
^Z
[1]+ Detenido ./test.sh
dione@saturno:~$ fg %1
./test.sh
4
5
6
^Z
[1]+ Detenido ./test.sh
dione@saturno:~$ %1 &
[1]+ ./test.sh &
dione@saturno:~$ 7
8
9
10
11
12
13
14
15
fg
./test.sh
16
17
^C
dione@saturno:~$
2 ответа
Перенаправление вывода работающего процесса не так просто. Но могут быть альтернативы, если вы работаете с самого начала:
some_long_runnning_command | tail -n 1000 & pkill -STOP tail
С этим методом, так как tail
имеет SIGSTOP
отправленный на него, он ничего не выведет, пока вы явно не выведете его на передний план, используя fg
(или что-то подобное) и до тех пор, пока сценарий не закончится. Настроить 1000
чтобы получить столько строк, сколько вы хотите.
Лучшая альтернатива может быть grep
:
some_long_runnning_command | grep . --color=never & pkill -STOP sed
Вы можете сигнализировать SIGCONT
а также SIGSTOP
в grep
начать и остановить вывод, как вы хотите.
Вероятно, это может быть объединено с повторным присоединением дескрипторов открытых файлов из вопроса SO, связанного выше (возможно, со сценарием в этом ответе), так что это может быть сделано с уже открытыми процессами.
Если буферизация действительно является проблемой с grep
Как указывает Фолькер Сигел, можно рассмотреть возможность использования более сложного набора команд. Во-первых, обратите внимание, что sort
использует временные файлы, поэтому буферизация не должна быть проблемой для него. Это будет действовать как сочетание tail
а также grep
- ожидание, пока команда не закончится, как tail
и сохраняя весь вывод, как grep
, Что-то вроде:
some_long_runnning_command | awk '{$0=";"$0}1' | sort -k1.1,1.1 --stable | sed 's/^;//' & pkill -STOP sed
Потеря здесь в том, что вы не можете запускать и останавливать вывод по желанию, и есть огромные вычисления, затраченные на бесполезные sort
а также работы, затраченные на добавление и удаление ;
,
Дальнейшие тесты показывают, что Volker действительно прав:
Для сценария, как (назовите его test.sh
):
#! /bin/bash
for i in $(seq 1000000); do echo $i; echo $i > /tmp/log; done
и команда:
./test.sh | grep . --color=never & pkill -STOP grep
число в /tmp/log
застрял на 12768 (с аналогичным показателем для. и с командой
./test.sh | awk '{$0=";"$0}1' | sort -k1.1,1.1 --stable | sed 's/^;//' & pkill -STOP sed
Сценарий запущен до завершения (/tmp/log
имел 1000000
) без писка от sed
,
Мне до сих пор не удалось интегрировать это с методом GDB, но это так, как оно есть, можно сделать так, чтобы оно функционировало как функция, аналогичная John1024. Проблема в том, что у вас нет хорошего способа узнать, завершился ли процесс, так как оболочка уведомляет вас только о завершении всей работы. Так что вам придется использовать функцию проверки:
function check ()
{
local PROC=${1:-$(jobs -p %%)}
kill -0 $PROC 2>/dev/null && echo "The process is still running." || echo "The process is not running."
}
function bg ()
{
"$@" | awk '{$0=";"$0}1' | sort -k1.1,1.1 --stable | sed 's/^;//' &
local PID=$!
sleep 0.1s
kill -STOP $PID
cat <<EOF
To get the output, do:
kill -CONT $PID
To check if the process has finished, do:
check $(jobs -p %%)
EOF
}
Вы могли бы обернуть "$@"
в другой функции, которая уведомит вас, как только работа будет выполнена, используя что-то вроде notify-send
или же write
,
Это было хорошее упражнение, но в конечном итоге самый простой способ - это /dev/null
и забудьте вывод: как перенаправить вывод приложения в фоновом режиме в / dev / null.
Этот скрипт перенаправляет стандартный вывод на /dev/null
только если скрипт работает в фоновом режиме:
#!/bin/sh
case "$(ps -o stat= -p $$)" in
*+*) : ;;
*) exec 1>/dev/null ;;
esac
for i in $(seq 200); do
echo $i
done
Ключевым моментом здесь является то, что ps
stat
поле имеет +
в нем, когда работа на переднем плане. Если +
отсутствует, мы в фоновом режиме.
Если вы хотите сохранить стандартный вывод для некоторых вещей, но не для других, мы можем создать файловый дескриптор 3 для дискреционного вывода и сохранить активный вывод для другого вывода. Сценарий ниже реализует это. Он отправляет выходные данные цикла в файловый дескриптор 3. Описание файла 3 либо stdout, если задание выполняется на переднем плане, либо /dev/null
если он работает в фоновом режиме:
#!/bin/sh
case "$(ps -o stat= -p $$)" in
*+*) exec 3<&1 ;;
*) exec 3>/dev/null ;;
esac
for i in $(seq 200); do
echo $i
done >&3
Простой способ выполнить любую команду в фоновом режиме и тихо
Создайте эту функцию bash:
bkg() { "$@" >/dev/null & }
Затем в любое время, когда вы хотите шумную команду, скажем seq 200
в фоновом режиме введите:
bkg seq 200
Команда будет выполняться в фоновом режиме, и ее стандартный вывод будет удален.
Чтобы дать определение bkg
постоянный, поместите определение в ~/.bashrc
,