Скройте stdout процесса только, когда он будет работать в фоне

Как я мог скрыть стандартный вывод процесса только, когда он работает в фоне?

Например,

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:~$ 
3
задан 17 September 2014 в 06:00

2 ответа

Этот сценарий перенаправляет stdout к /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 поле имеет a + в нем, когда задание является передним планом. Если + отсутствует, мы находимся в фоне.

Если Вы хотите иметь в наличии stdout для некоторых вещей, но не других, мы можем создать дескриптор файла 3 для дискреционного вывода и сохранить stdout активный для другого вывода. Сценарий ниже реализует это. Это отправляет вывод цикла в дескриптор файла 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

Простой способ выполнить любую команду в фоне и тихо

Создайте эту функцию удара:

bkg() { "$@" >/dev/null & }

Затем в любое время то, что Вы хотите к шумной команде, сказать seq 200, в фоне введите:

bkg seq 200

Команда будет выполнена в фоне, и от его stdout избавятся.

Сделать определение bkg постоянный, поместите определение в ~/.bashrc.

1
ответ дан 17 November 2019 в 20:50

Перенаправление вывода рабочего процесса не легко. Но могли бы быть альтернативы, если Вы работаете от запуска:

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 запустить и остановить вывод, как Вы хотите.

Это может, вероятно, быть объединено с прикреплением открытых дескрипторов файлов от ТАК вопрос, связанный выше (возможно, со сценарием в этом ответе) так, чтобы это могло быть сделано с процессами, уже открытыми.


Если буферизация является действительно проблемой с grep, как Volker Siegel указывает, затем можно было бы рассмотреть использование более сложного набора команд. Во-первых, отметьте это 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 застрял в 12 768 (с подобной фигурой для. И с командой

./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.

2
ответ дан 1 December 2019 в 16:29

Другие вопросы по тегам:

Похожие вопросы: