如何从父外壳中的子外壳中获取变量


11

我编写了一个简单的脚本来为Web服务中的一些报告计时:

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命令包装在子外壳中,以便可以重定向其输出,但是这会使$response父外壳无法使用该值。我该如何解决这个问题?

Answers:


11

您不能将变量的值从子shell传递给它的父对象,除非没有进行一些容易出错的编组和麻烦的通信。

幸运的是,您在这里不需要子shell。重定向只需要命令分组{ … },而不是一个子shell。

{ time -p response=$(curl --write-out '%{http_code}' --silent -O "${BASE_URL}/${report_code}"); } 2> "${report_code}.time"

(不要忘记在变量替换处使用双引号。)


有趣的是,每种编程语言都可以做到这一点。我已经在谷歌上搜索了1h,而在shell中没有可能的解决方案。我很失望。
致Kra 2013年

1
@ToKra否。没有编程语言可以做到这一点。(几乎)任何编程语言都可以将变量的值从子例程或指令块带到其父对象,而这正是我在回答中解释的内容:使用命令分组{ … }而不是subshel​​l ( … )
吉尔(Gilles)“所以,别再邪恶了”

4

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次迭代之后,该变量被修改了。


嗯,对于C程序员来说是非直觉的行为。我通常希望outter引用的全局实例var
罗斯兰

这个答案有一些缺陷。"$var"呼出不需要outter。它什么也没做。而且local var=0什么也不做;如您所说,调用ouf outter确实会覆盖var
Golar Ramblar

我已经将@GolarRamblar删除"$var"为位置参数outter;公平地说,这是一种习惯。您能详细说明一下local var=0 吗?
Sergiy Kolodyazhnyy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.