bash 从子shell设置父shell的变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15541321/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Set a parent shell's variable from a subshell
提问by Matt Joiner
How do I set a variable in the parent shell, from a subshell?
如何从子外壳在父外壳中设置变量?
a=3
(a=4)
echo $a
回答by cdarke
The whole point of a subshell is that it doesn'taffect the calling session. In bash a subshell is a child process, other shells differ but even then a variable setting in a subshell does not affect the caller. By definition.
子shell的全部意义在于它不会影响调用会话。在 bash 中,子外壳是子进程,其他外壳不同,但即使如此,子外壳中的变量设置也不会影响调用者。根据定义。
Do you need a subshell? If you just need a group then use braces:
你需要一个子外壳吗?如果您只需要一个组,请使用大括号:
a=3
{ a=4;}
echo $a
gives 4
(be careful of the spaces in that one). Alternatively, write the variable value to stdout and capture it in the caller:
给出4
(注意那个空格中的空格)。或者,将变量值写入 stdout 并在调用者中捕获它:
a=3
a=$(a=4;echo $a)
echo $a
avoid using back-ticks ``, they are deprecated and can be difficult to read.
避免使用反引号``,它们已被弃用并且可能难以阅读。
回答by BeniBela
There is the gdb-bash-variable hack:
有 gdb-bash-variable hack:
gdb --batch-silent -ex "attach $$" -ex 'set bind_variable("a", "4", 0)';
although that always sets a variable in the global scope, not just the parent scope
尽管这总是在全局范围内设置一个变量,而不仅仅是父范围
回答by ruakh
You don't. The subshell doesn't have access to its parent's environment. (At least within the abstraction that Bash provides. You could potentially try to use gdb
, or smash the stack, or whatnot, to gain such access clandestinely. I wouldn't recommend that, though.)
你没有。子shell 无权访问其父级的环境。(至少在 Bash 提供的抽象中。您可能会尝试使用gdb
或粉碎堆栈或诸如此类的东西来秘密获得此类访问权限。不过,我不建议这样做。)
One alternative is for the subshell to write assignment statements to a temporary file for its parent to read:
一种替代方法是让子 shell 将赋值语句写入临时文件以供其父级读取:
a=3
(echo 'a=4' > tmp)
. tmp
rm tmp
echo "$a"
回答by marioquark
If the problem is related to a while loop, one way to fix this is by using Process Substitution:
如果问题与 while 循环有关,解决此问题的一种方法是使用进程替换:
var=0
while read i;
do
# perform computations on $i
((var++))
done < <(find . -type f -name "*.bin" -maxdepth 1)
as shown here: https://stackoverflow.com/a/13727116/2547445
回答by Carl Bosch
To change variables in a script called from a parent script, you can call the script preceded with a "."
要更改从父脚本调用的脚本中的变量,您可以调用以“.”开头的脚本。
a=3
echo $a
. ./calledScript.sh
echo $a
in calledScript.sh
在调用Script.sh
a=4
Expected output
预期输出
3
4
回答by khachik
You can output the value in the subshell and assign the subshell output to a variable in the caller script:
您可以在子shell中输出值并将子shell输出分配给调用者脚本中的变量:
# subshell.sh
echo Value
# caller
myvar=$(subshell.sh)
If the subshell has more to output you can separate the variable value and other messages by redirecting them into different output streams:
如果子shell有更多输出,您可以通过将变量值和其他消息重定向到不同的输出流来分离它们:
# subshell.sh
echo "Writing value" 1>&2
echo Value
# caller
myvar=$(subshell.sh 2>/dev/null) # or to somewhere else
echo $myvar
Alternatively, you can output variable assignments in the subshell, evaluate them in the caller script and avoid using files to exchange information:
或者,您可以在子 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
The last way I can think of is to use exit codes but this covers the integer values exchange only (and in a limited range) and breaks the convention for interpreting exit codes (0 for success non-0 for everything else).
我能想到的最后一种方法是使用退出代码,但这仅涵盖整数值交换(并且在有限的范围内)并打破了解释退出代码的约定(0 表示成功非 0 表示其他所有内容)。
回答by Paul
Unless you can apply all io to pipes and use file handles, basic variable updating is impossible within $(command) and any other sub-process.
除非您可以将所有 io 应用于管道并使用文件句柄,否则在 $(command) 和任何其他子进程中基本变量更新是不可能的。
Regular files, however, are bash's global variables for normal sequential processing. Note: Due to race conditions, this simple approach is not good for parallel processing.
然而,常规文件是用于正常顺序处理的 bash 全局变量。注意:由于竞争条件,这种简单的方法不适用于并行处理。
Create an set/get/default function like this:
创建一个 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" "" > "$aRam/globalVariable"
fi
}
"$aRam" is the directory where values are stored. I like it to be a ram disk for speed and volatility:
“$aRam”是存储值的目录。我喜欢它是速度和波动性的 ram 磁盘:
aRam="$(mktemp -td $(basename "v="$(globalVariable)" # or part of any command
").XXX)" # temporary directory
mount -t tmpfs ramdisk "$aRam" # mount the ram disk there
trap "umount "$aRam" && rm -rf "$aRam"" EXIT # auto-eject
To read the value:
要读取值:
globalVariable newValue # newValue will be written to file
To set the value:
要设置值:
rm -f "$aRam/globalVariable"
To unset the value:
要取消设置值:
v="$(cat "$aRam/globalVariable 2>/dev/null")"
The only real reason for the access function is to apply a default value because cat will error given a non-existent file. It is also useful to apply other get/set logic. Otherwise, it would not be needed at all.
访问函数的唯一真正原因是应用默认值,因为如果文件不存在, cat 会出错。应用其他 get/set 逻辑也很有用。否则,根本不需要它。
An ugly read method avoiding cat's non-existent file error:
一种避免 cat 不存在文件错误的丑陋读取方法:
##代码##A cool feature of this mess is that you can open another terminal and examine the contents of the files while the program is running.
这种混乱的一个很酷的功能是您可以在程序运行时打开另一个终端并检查文件的内容。