Скрыть стандартный вывод процесса, только если он запущен в фоновом режиме

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

Например,

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

Ключевым моментом здесь является то, что psstat поле имеет + в нем, когда работа на переднем плане. Если + отсутствует, мы в фоновом режиме.

Если вы хотите сохранить стандартный вывод для некоторых вещей, но не для других, мы можем создать файловый дескриптор 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,

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