我正在处理这个问题:
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
我有一个如下脚本:
#!/bin/bash
e=2
function test1() {
e=4
echo "hello"
}
test1
echo "$e"
返回:
hello
4
但是如果我将函数的结果赋给变量,则不会修改全局变量e
:
#!/bin/bash
e=2
function test1() {
e=4
echo "hello"
}
ret=$(test1)
echo "$ret"
echo "$e"
返回:
hello
2
在这种情况下我听说过the use of eval,所以我在test1
中这样做了:
eval 'e=4'
但结果相同。
你能解释一下为什么不修改它吗?如何在test1
中保存ret
函数的回声并修改全局变量?
答案 0 :(得分:73)
当您使用命令替换(即$(...)
构造)时,您正在创建子shell。子shell从其父shell继承变量,但这只能以一种方式工作 - 子shell无法修改其父shell的环境。您的变量e
在子shell中设置,但不在父shell中设置。将值从子shell传递到其父级有两种方法。首先,您可以输出一些内容到stdout,然后使用命令替换来捕获它:
myfunc() {
echo "Hello"
}
var="$(myfunc)"
echo "$var"
给出:
Hello
对于0-255之间的数值,您可以使用return
将数字作为退出状态传递:
mysecondfunc() {
echo "Hello"
return 4
}
var="$(mysecondfunc)"
num_var=$?
echo "$var - num is $num_var"
给出:
Hello - num is 4
答案 1 :(得分:13)
也许你可以使用一个文件,写入文件里面的函数,然后从文件中读取。我已将e
更改为数组。在这个例子中,当读回数组时,空格被用作分隔符。
#!/bin/bash
declare -a e
e[0]="first"
e[1]="secondddd"
function test1 () {
e[2]="third"
e[1]="second"
echo "${e[@]}" > /tmp/tempout
echo hi
}
ret=$(test1)
echo "$ret"
read -r -a e < /tmp/tempout
echo "${e[@]}"
echo "${e[0]}"
echo "${e[1]}"
echo "${e[2]}"
输出:
hi
first second third
first
second
third
答案 2 :(得分:11)
你在做什么,你正在执行test1
$(test1)
在子shell(子shell)中,子shell无法修改父级中的任何内容。
您可以在bash manual
中找到它请检查:事情产生子shell here
答案 3 :(得分:4)
当我想自动删除我创建的临时文件时,我遇到了类似的问题。我想出的解决方案不是使用命令替换,而是将应该取最终结果的变量名称传递给函数。 E.g。
#! /bin/bash
remove_later=""
new_tmp_file() {
file=$(mktemp)
remove_later="$remove_later $file"
eval $1=$file
}
remove_tmp_files() {
rm $remove_later
}
trap remove_tmp_files EXIT
new_tmp_file tmpfile1
new_tmp_file tmpfile2
所以,在你的情况下,这将是:
#!/bin/bash
e=2
function test1() {
e=4
eval $1="hello"
}
test1 ret
echo "$ret"
echo "$e"
工作并且对“返回值”没有限制。
答案 4 :(得分:1)
这是因为命令替换是在子shell中执行的,所以当子shell继承变量时,当子shell结束时,它们的更改会丢失。
命令替换,用括号分组的命令和异步命令在子shell环境中调用,该环境与shell环境重复
答案 5 :(得分:1)
此问题的一种解决方案是将值存储在一个临时文件中,并在需要时进行读取/写入,而无需引入复杂的功能并大量修改原始功能。
当我不得不在bats测试用例中多次模拟bash函数时,这种方法对我有很大帮助。
例如,您可能拥有:
# Usage read_value path_to_tmp_file
function read_value {
cat "${1}"
}
# Usage: set_value path_to_tmp_file the_value
function set_value {
echo "${2}" > "${1}"
}
#----
# Original code:
function test1() {
e=4
set_value "${tmp_file}" "${e}"
echo "hello"
}
# Create the temp file
# Note that tmp_file is available in test1 as well
tmp_file=$(mktemp)
# Your logic
e=2
# Store the value
set_value "${tmp_file}" "${e}"
# Run test1
test1
# Read the value modified by test1
e=$(read_value "${tmp_file}")
echo "$e"
缺点是您可能需要多个临时文件来存储不同的变量。另外,您可能需要发出sync
命令以在一次写入和读取操作之间将内容持久存储在磁盘上。
答案 6 :(得分:1)
假设 local -n
可用,以下脚本让函数 test1
修改全局变量:
#!/bin/bash
e=2
function test1() {
local -n var=$1
var=4
echo "hello"
}
test1 e
echo "$e"
给出以下输出:
hello
4
答案 7 :(得分:-1)
您始终可以使用别名:
alias next='printf "blah_%02d" $count;count=$((count+1))'