Я пытаюсь сделать что-то, что включает в себя сценарии, вызывающие другие сценарии в подоболочках для захвата их вывода.

Один из сценариев должен иметь побочный эффект запуска фонового процесса. Все это работает при непосредственном выполнении, но блокируется при вызове в подоболочке.

В качестве отдельного примера рассмотрим следующие 2 сценария:

test1.sh

#!/bin/bash
echo $(./test2.sh)

test2.sh

#!/bin/bash
(yes > /dev/null ; echo 'yes killed') &
echo success

Когда я запускаю test2.sh сам по себе, я получаю ожидаемый результат "успеха" на терминале и yes работающий в фоновом режиме. Killing yes печатает "yes kill" в терминал, как и ожидалось.
Когда я запускаю test1.sh я ожидаю, что получу то же самое поведение, но на самом деле происходит то, что терминал зависает до тех пор, пока я не убью yes после чего на терминал выводится "успех да уничтожен" .

Что я могу изменить в этих сценариях, чтобы получить одинаковое поведение при вызове любого из них?

Предполагается, что оценка подоболочки в test1.sh будет храниться в переменной для последующего использования. Фоновый процесс, запущенный в test2.sh должен проходить после выполнения любого сценария.

4 ответа4

3

Подстановка команд $(...) превращает вывод в аргументы. Сначала нужен весь вывод, потому что он не может предоставлять аргументы динамически один за другим.

1

Как предложили @choroba и @GordonDavisson, подстановка команд $( ... ) не вернется, пока не отключится весь ее стандартный вывод [1].

Хитрость в том, что даже если вы перенаправляете все stdout команд, то есть собственно подоболочка. ( ... ) все еще имеет свой стандартный вывод. Это означает, что следующее не будет работать:

#!/bin/bash
(yes > /dev/null ; echo 'yes killed' > /dev/null) &
echo success

Но это будет:

#!/bin/bash
(yes ; echo 'yes killed' ) > /dev/null &
echo success

Примечание: вы больше не будете получать вывод на терминал или стандартный вывод, как это, но для моей цели это не проблема. При необходимости вы всегда можете перенаправить в файл или что-то, если нужен вывод


[1] См. Также https://stackoverflow.com/questions/16874043/bash-command-substitution-forcing-process-to-foreground

1

Я думаю, что отречение Баша является ответом. Смотрите help disown .

Используйте это так:

yes &>/dev/null </dev/zero &
disown -h $!

Перенаправление вывода или закрытие терминала приведет к тому, что сигнал SIGHUP или прерванный канал для выхода (SIGPIPE) в конечном итоге заблокируют или убьют программу.

Если вы заботитесь о выводе, перенаправьте его в файл. Или используйте nohup вот так:

nohup yes &
disown $!

Хорошее объяснение nohup и отречения.

0

Вам не нужно echo для запуска другого скрипта

#!/bin/bash
#echo $(./test2.sh)
./test2.sh

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .