如何在子shell中设置变量?
a=3
(a=4)
echo $a
答案 0 :(得分:43)
子shell的重点是不会影响调用会话。在bash中,子shell是子进程,其他shell有所不同,但即使这样,子shell中的变量设置也不会影响调用者。根据定义。
你需要一个子壳吗?如果你只需要一个小组,那就使用大括号:
a=3
{ a=4;}
echo $a
给出4
(小心那个中的空格)。或者,将变量值写入stdout并在调用者中捕获它:
a=3
a=$(a=4;echo $a)
echo $a
避免使用back-ticks``,它们已被弃用且难以阅读。
答案 1 :(得分:30)
有gdb-bash-variable hack:
gdb --batch-silent -ex "attach $$" -ex 'set bind_variable("a", "4", 0)';
虽然它始终在全局范围内设置变量,而不仅仅是父范围
答案 2 :(得分:21)
你没有。子shell无法访问其父级环境。 (至少在Bash提供的抽象中。你可能会尝试使用gdb
,或者粉碎堆栈,或者诸如此类,以秘密获取此类访问权限。但我不建议这样做。)
另一种方法是让子shell将赋值语句写入临时文件,以使其父级读取:
a=3
(echo 'a=4' > tmp)
. tmp
rm tmp
echo "$a"
答案 3 :(得分:10)
如果问题与while循环有关,解决此问题的一种方法是使用Process Substitution:
"H","9","YES","NO","4,5","Y","N" would become this:
"H","9","YES","NO","4|5","Y","N"
答案 4 :(得分:5)
要更改从父脚本调用的脚本中的变量,可以调用前面带有"。"
的脚本。a=3
echo $a
. ./calledScript.sh
echo $a
在calledScript.sh
中a=4
预期输出
3
4
答案 5 :(得分:4)
您可以在子shell中输出值,并将子shell输出分配给调用者脚本中的变量:
# subshell.sh
echo Value
# caller
myvar=$(subshell.sh)
如果子shell有更多输出,你可以通过将它们重定向到不同的输出流来分离变量值和其他消息:
# subshell.sh
echo "Writing value" 1>&2
echo Value
# caller
myvar=$(subshell.sh 2>/dev/null) # or to somewhere else
echo $myvar
或者,您可以在子shell中输出变量赋值,在调用者脚本中对它们进行评估,并避免使用文件来交换信息:
# 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表示其他所有内容)。
答案 6 :(得分:0)
除非可以将所有io应用于管道并使用文件句柄,否则$(command)和任何其他子进程中的基本变量更新是不可能的。
但是,常规文件是bash的全局变量,用于常规顺序处理。注意:由于竞争条件,这种简单的方法不适用于并行处理。
创建这样的set / get / default函数:
globalVariable() { # NEW-VALUE
# set/get/default globalVariable
if [ 0 = "$#" ]; then
# new value not given -- echo the value
[ -e "$aRam/globalVariable" ] \
&& cat "$aRam/globalVariable" \
|| printf "default-value-here"
else
# new value given -- set the value
printf "%s" "$1" > "$aRam/globalVariable"
fi
}
“ $ aRam”是存储值的目录。我喜欢将其作为具有速度和波动性的ram磁盘:
aRam="$(mktemp -td $(basename "$0").XXX)" # temporary directory
mount -t tmpfs ramdisk "$aRam" # mount the ram disk there
trap "umount "$aRam" && rm -rf "$aRam"" EXIT # auto-eject
要读取值:
v="$(globalVariable)" # or part of any command
要设置值:
globalVariable newValue # newValue will be written to file
要取消设置值:
rm -f "$aRam/globalVariable"
访问功能的唯一真正原因是应用默认值,因为如果文件不存在,cat将会出错。应用其他获取/设置逻辑也很有用。否则,将根本不需要它。
避免猫不存在的文件错误的丑陋读取方法:
v="$(cat "$aRam/globalVariable 2>/dev/null")"
此混乱的一个很酷的功能是,您可以在程序运行时打开另一个终端并检查文件的内容。
答案 7 :(得分:0)
不要从父 shell 访问变量,而是更改命令的顺序并使用 process substitution:
a=3
echo 5 | (read a)
echo $a
打印 3
a=3
read a < <(echo 5)
echo $a
打印 5
另一个例子:
let i=0
seq $RANDOM | while read r
do
let i=r
done
echo $i
对比
let i=0
while read r
do
let i=r
done < <(seq $RANDOM)
echo $i
或者,当作业控制处于非活动状态时(例如在脚本中),您可以使用 lastpipe
shell 选项来获得相同的结果,而无需更改命令的顺序:
#!/bin/bash
shopt -s lastpipe
let i=0
seq $RANDOM | while read r
do
let i=r
done
echo $i
答案 8 :(得分:0)
一个非常简单实用的允许多个变量的方法如下,最终可能会在调用中添加参数:
function ComplexReturn(){
# do your processing...
a=123
b=456
echo -n "AAA=${a}; BBB=${b};"
}
# ... this can be internal function or any subshell command
eval $(ComplexReturn)
echo $AAA $BBB