2013-03-21 4 views

ответ

34

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

Вам нужна подоболочка? Если вам просто нужна группа, то использовать фигурные скобки:

a=3 
{ a=4;} 
echo $a 

дает 4 (быть осторожными пространства в том, что один). В качестве альтернативы, записать значение переменной на стандартный вывод и захватить его в вызывающем:

a=3 
a=$(a=4;echo $a) 
echo $a 

избегают использования обратно-тиков ``, они являются устаревшими и могут быть трудно читать.

+0

Спасибо, что указали на фигурные скобки. Я видел их, но никогда не знал, что они сделали, и не использовал их. Хороший совет! – Christian

17

У вас нет. У подоболочки нет доступа к среде своего родителя. (По крайней мере, в пределах абстракции, которую предоставляет Bash. Вы могли бы попытаться использовать gdb или разбить стек или что-то еще, чтобы получить такой доступ подпольно. Я бы не рекомендовал этого.)

Один из вариантов для подоболочка писать заявления о назначении на временный файл для его родителя следующим образом:

a=3 
(echo 'a=4' > tmp) 
. tmp 
rm tmp 
echo "$a" 
+0

Не очень, но в значительной степени лучший вариант в некоторых случаях. Спасибо. –

+1

Файловый подход весьма полезен, если вы используете подоболочку для сбора значений для m которые потребуются родительской оболочке позже, особенно в тех случаях, когда использование нечеткой подоболочки не является тривиальным. – aroth

+0

Мне пришлось использовать это, потому что я использовал «set -u» и «set -e» в начале моего основного скрипта, но мне нужно было запустить некоторые команды, чтобы установить переменную, которая выходит с ненулевым кодом выхода (и тем самым вызывая «-e», чтобы убить скрипт). –

3

Вы можете вывести значение в субоболочке и назначить выход подоболочку к переменной в скрипте вызывающего абонента:

# subshell.sh 
echo Value 

# caller 
myvar=$(subshell.sh) 

флигель имеет больше выход можно разделить значение переменного и другие сообщения, перенаправляя их в различные выходных потоков:

# subshell.sh 
echo "Writing value" 1>&2 
echo Value 

# caller 
myvar=$(subshell.sh 2>/dev/null) # or to somewhere else 
echo $myvar 

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

# subshell.sh 
echo "a=4" 

# caller 
# export $(subshell.sh) would be more secure, since export accepts name=value only. 
eval $(subshell.sh) 
echo $a 

последним способом, которым я могу думать о том, чтобы использовать коды выхода, но это охватывает обмен целых значений только (и в ограниченном диапазоне) и нарушает конвенцию для интерпретации кодов выхода (0 для успеха не-0 для всего остального).

21

Существует GDB-баш-переменная хак:

gdb --batch-silent -ex "attach $$" -ex 'set bind_variable("a", "4", 0)'; 

хотя это всегда устанавливает переменную в глобальном масштабе, а не только родительской сферу

+14

Хотя это менее опасно, я бы сказал, что это должно использоваться так часто, как вилка в реальном сценарии. – chepner

+29

+1 для удивительного. -1 для чистого террора. –

+0

Я должен был «...» прикрепить $ PPID «...», чтобы сделать эту работу - $$ содержит PID текущей оболочки. – dingalapadum

6

Если проблема связана с временем цикла , один из способов исправить это с помощью процесса замещения:

var=0 
    while read i; 
    do 
     # perform computations on $i 
     ((var++)) 
    done < <(find . -type f -name "*.bin" -maxdepth 1) 

, как показано здесь: https://stackoverflow.com/a/13727116/2547445

0

Чтобы изменить переменные в скрипте, вызванном из родительского скрипта, вы можете вызвать сценарий, которому предшествует «."

a=3 
echo $a  
. ./calledScript.sh 
echo $a 

в calledScript.sh

a=4 

Ожидаемый результат

3 
4 
Смежные вопросы