Вам нужно сказать теперь фоновому приложению, чтобы оно остановилось запись на устройстве tty. Нет универсального способа сделать это.
Вы можете:
stty tostop
сделать так, чтобы фоновые задания приостанавливались (с сигналом SIGTTOU
) при попытке записи на tty.
Вы можете присоединить к процессу отладчик и заставить его повторно открывать файловые дескрипторы, открытые на tty-устройстве, в / dev / null
. Например (здесь только для stdout):
gdb --batch -ex 'call close(1)' -ex 'call open("/dev/null",2)' -p "$pid"
(при условии, что приложение динамически связано или имеет символы отладки, и обратите внимание, что некоторые системы будут иметь ограничения безопасности, мешающие вам это сделать).
Для динамически связанных приложений вы можете запустить их с помощью большого двоичного объекта LD_PRELOAD
, который устанавливает обработчик на SIGTTOU (и выполняет stty tostop
), который повторно открывает stdout и stderr на / dev / null
, если они собирались использовать терминал. Это будет обрабатывать случай, когда приложения, отличные от setuid / setgid, записываются на терминал через их stdout / stderr и не обрабатывают SIGTTOU сами.
Выполнить:
gcc -Wall -shared -fPIC -nostartfiles -o ~/lib/handle_tostop.so handle_tostop.c
Где handle_tostop.c
содержит:
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static void reopen_on_null(int req_fd)
{
int fd;
if (close(req_fd) == 0) {
fd = open("/dev/null", O_RDWR);
if (fd != req_fd && fd >= 0) {
dup2(fd, req_fd);
close(fd);
}
}
}
static void handle_sigttou(int sig)
{
if (isatty(1)) reopen_on_null(1);
if (isatty(2)) reopen_on_null(2);
}
void _init()
{
signal(SIGTTOU, handle_sigttou);
}
А затем:
LD_PRELOAD=~/lib/handle_tostop.so
export LD_PRELOAD
stty tostop
Вместо / dev / null
вы можете перенаправить вывод в какой-либо файл журнала (который затем вы можете открыть с помощью ] O_APPEND
и, возможно, включите pid процесса в имя файла, чтобы вы знали, чей процесс выводится), чтобы он не отбрасывался, если он вам пригодится.
Для переменных можно использовать анонимную функцию (как указано в комментарии выше). Это означает, что вы можете определить столько переменных, сколько захотите. Те, которые вы хотите скрыть от вызывающего абонента, вы ставите префиксом local
, те, которые вы хотите передать вызывающему абоненту, вы просто определяете как обычно:
function {
local my_var=foo
your_var=bar
: ...
}
Но для функций, которые не будут работать, поскольку они не могут быть объявлены местный
. У меня была эта проблема в моем zshrc , и я решил добавить ко всем именам моих «локальных» функций короткую строку (как вы делаете пространства имен в C) и выполнить функцию подстановочного знака
в конец:
function foo-do-something () {
: ...
}
function foo-do-some-more-stuff () {
: ...
}
function foo-main () {
local my_var=oof
you_var=rab
foo-do-something for bar
foo-do-some-more-stuff with baz
}
foo-main
unfunction -m 'foo-*'
На мой взгляд, это не оптимальное решение (я бы предпочел локальные функции), но у меня оно работает.
Решение заключается в использовании подоболочек, вложенных функций и unset
для основной функции:
my_app_main()
(
unset -f my_app_main
a()
(
x=1
echo "a.x is $x"
)
b()
(
x=2
echo "b.x is $x"
)
c()
(
echo "c.x is $x (empty)"
)
a
b
c
)
my_app_main "$@"
echo "$x (empty - x is gone)"
# all gone
type my_app_main a b c