Как прочитать ввод с клавиатуры и присвоить его локальной переменной?

Какая оболочка используется, вызывает беспокойство, поскольку разные оболочки по-разному обрабатывают управление заданиями (, а управление заданиями усложнено; job.cв bashв настоящее время весит 3300 строк C согласно cloc). Например, pdksh5.2.14 по сравнению с bash3.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$ 
1
12.11.2019, 17:20
1 ответ

Локальная встроенная функция работает только внутри функции. Любая переменная, которую вы устанавливаете в своем скрипте, уже будет "локальной" для скрипта, если только вы явно не 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
2
27.01.2020, 23:29

Теги

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