Какая оболочка используется, вызывает беспокойство, поскольку разные оболочки по-разному обрабатывают управление заданиями (, а управление заданиями усложнено; job.c
в bash
в настоящее время весит 3300 строк C согласно cloc
). Например, pdksh
5.2.14 по сравнению с bash
3.2 в Mac OS X 10.11 показывает:
$ cat code
pkill yes
yes >/dev/null &
pid=$!
echo $pid
sleep 2
kill -INT $pid
sleep 2
pgrep yes
$ bash code
38643
38643
$ ksh code
38650
$
Также уместно здесь то, что yes
не выполняет никакой обработки сигналов, поэтому наследует все, что должно быть унаследовано от родительского процесса оболочки; если, напротив, мы выполняем обработку сигналов—
$ cat sighandlingcode
perl -e '$SIG{INT} = sub { die "ouch\n" }; sleep 5' &
pid=$!
sleep 2
kill -INT $pid
$ bash sighandlingcode
ouch
$ ksh sighandlingcode
ouch
$
— SIGINT запускается независимо от родительской оболочки, так как perl
здесь, в отличие от yes
, изменил обработку сигнала. Существуют системные вызовы, относящиеся к обработке сигналов, которые можно наблюдать с помощью таких вещей, как DTrace или здесь strace
в Linux:
-bash-4.2$ cat code
pkill yes
yes >/dev/null &
pid=$!
echo $pid
sleep 2
kill -INT $pid
sleep 2
pgrep yes
pkill yes
-bash-4.2$ rm foo*; strace -o foo -ff bash code
21899
21899
code: line 9: 21899 Terminated yes > /dev/null
-bash-4.2$
Мы обнаружили, что процесс yes
завершается SIGINT
игнорированием:
-bash-4.2$ egrep 'exec.*yes' foo.21*
foo.21898:execve("/usr/bin/pkill", ["pkill", "yes"], [/* 24 vars */]) = 0
foo.21899:execve("/usr/bin/yes", ["yes"], [/* 24 vars */]) = 0
foo.21903:execve("/usr/bin/pgrep", ["pgrep", "yes"], [/* 24 vars */]) = 0
foo.21904:execve("/usr/bin/pkill", ["pkill", "yes"], [/* 24 vars */]) = 0
-bash-4.2$ grep INT foo.21899
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f18ebee0250}, {SIG_DFL, [], SA_RESTORER, 0x7f18ebee0250}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f18ebee0250}, {SIG_DFL, [], SA_RESTORER, 0x7f18ebee0250}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN, [], SA_RESTORER, 0x7f18ebee0250}, {SIG_DFL, [], SA_RESTORER, 0x7f18ebee0250}, 8) = 0
--- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=21897, si_uid=1000} ---
-bash-4.2$
Повторите этот тест с кодом perl
, и вы должны увидеть, что SIGINT
не игнорируется, или также что в pdksh
не устанавливается игнорирование, как в bash
. При включенном «режиме монитора», как в интерактивном режиме в bash
, yes
уничтожается.
-bash-4.2$ cat monitorcode
#!/bin/bash
set -m
pkill yes
yes >/dev/null &
pid=$!
echo $pid
sleep 2
kill -INT $pid
sleep 2
pgrep yes
pkill yes
-bash-4.2$./monitorcode
22117
[1]+ Interrupt yes > /dev/null
-bash-4.2$
Локальная встроенная функция работает только внутри функции. Любая переменная, которую вы устанавливаете в своем скрипте, уже будет "локальной" для скрипта, если только вы явно не export
это сделаете. Поэтому, если вы удалите это, он будет работать как положено:
#!/bin/bash
read _test
echo "_test: $_test"
Или вы можете сделать это функцией:
my_read () {
local _test
read _test
echo "_test: $_test"
}
Даже внутри функции встроенная функция local
не будет работать так, как вы ее написали:
Ваш код на самом деле устанавливает переменную с буквальным именемlocal
:
#!/bin/bash
read local _test
echo "_test: $_test"
echo "local: $local"
$./script.sh
sssss aaaaa
_test: aaaaa
local: sssss