我编写了一个快速而简单的脚本来对来自网络服务的一些报告进行计时:
BASE_URL='http://example.com/json/webservice/'
FIRST=1
FINAL=10000
for report_code in $(seq 1 $FINAL); do
(time -p response=$(curl --write-out %{http_code} --silent -O ${BASE_URL}/${report_code}) ) 2> ${report_code}.time
echo $response # <------- this is out of scope! How do I fix that?
if [[ $response = '404' ]]; then
echo "Deleting report # ${report_code}!"
rm ${report_code}
else
echo "${report_code} seems to be good!"
fi
done
我需要将time
命令包装在子 shell 中,以便可以重定向其输出,但这使得$response
父 shell 无法使用值。我该如何解决这个问题?
答案1
如果不进行一些容易出错的编组和繁琐的通信,就无法将变量的值从子 shell 传递到其父 shell。
幸运的是,这里不需要子 shell。重定向只需要命令分组与{ … }
,不是子外壳。
{ time -p response=$(curl --write-out '%{http_code}' --silent -O "${BASE_URL}/${report_code}"); } 2> "${report_code}.time"
(别忘了变量替换用双引号引起来.)
答案2
各位 U&L 用户:在否决我关于使用 C 风格main()
函数的答案之前,请访问此链接:https://unix.stackexchange.com/a/313561/85039在脚本中使用主要函数是一种常见做法,被该领域的许多专业人士使用。
正如 Gilles 指出的那样,子 shell 无法使变量在其环境之外可用。但是让我们从另一个角度来解决这个问题 - 如果您在函数中编写脚本,则可以将变量声明为local
且可以编辑。
来自bash 4.3的手册,local
描述:
...当在函数中使用 local 时,它会导致变量名称的可见范围仅限于该函数及其子函数...
例子:
#!/bin/bash
outter()
{
for i in $(seq 1 3)
do
var=$i
done
}
main()
{
local var=0
outter
echo $var
}
main "$@"
$ ./testscript.sh
3
正如您所看到的,循环函数迭代 3 次后,变量被修改。
答案3
您可以在 a 中重定向变量test.txt
并在父 shell 中获取它。
testfn()
{
echo "test" > test.txt # redirect your variable in a test.txt
}
testfn & # execute your function in the subshell
testresult=$(cat test.txt) # get your variable in the parent shell
printf '%s\n' "$testresult"
答案4
从 bash 4.3 开始,你可以这样做名称引用变量
#!/usr/bin/env bash
# outvar is a nameref variable that allows us to set the value of a variable
# outside our scope
addfoo() {
local x="$1"
local -n outvar=$2
x="foo$x"
outvar="$x"
}
declare b=“loll”
addfoo "bar" b
echo "$b”
这将foobar
在函数addfoo
修改b
变量时输出,即使b
超出了其范围。
Nameref 对于从函数中提取值而不使用子 shell 非常有用$(addfoo)
。