【问题标题】:Variables value gets lost in subshell变量值在子shell中丢失
【发布时间】:2010-06-21 14:31:00
【问题描述】:

此 bash 脚本将 jar 文件的名称连接到类路径(变量 CP),在 while 循环中,值是正确的,但在子shell 中丢失,如相关问题 Bash variable scope 中所述

#!/bin/bash
CP="AAA"
func() {
        ls -1 | while read JAR
        do
                if [ ! -z "$CP" ]; then
                        CP=${CP}':'
                fi
                CP=${CP}${JAR}
        done
        echo $CP # <-- prints AAA
}

func

我的问题是,由于我无法确定哪个元素将是最后一个元素,如何保存该值。

我是否真的必须将当前值(在循环中重复)保存到文件中?

编辑:

一位同事想出了这个运行良好的命令序列

ls | xargs echo|tr ' ' :

【问题讨论】:

    标签: bash unix scripting


    【解决方案1】:

    这里的问题是在管道中使用while 会创建一个子shell,而子shell 不能影响其父shell。您可以通过几种方式解决此问题。对于你现在正在做的事情,这就足够了:

    for JAR in *; do
        # Your stuff
    done
    

    另外需要注意的是你shouldn't rely on parsing ls

    This 还向您展示了避免使用 subshel​​l 的方法。

    【讨论】:

      【解决方案2】:

      您可能会发现使用 find 更加通用。

      例如:

      export CP=$( find /home/depesz/q/ -maxdepth 1 -type f -name '*.jar' -printf ':%p' | cut -b 2- )
      

      当然,查找选项集取决于您需要/想要的。

      这个更接近你之前的:

      export CP=$( find . -maxdepth 1 -type f -name '*.jar' -printf ':%f' | cut -b 2- )
      

      【讨论】:

        【解决方案3】:

        隐式子shell令人困惑;始终使用括号使它们显式。要解决您的问题,只需将 echo 移动到子外壳内即可。

        #!/bin/bash
        CP="AAA"
        func() {
          ls -1 | (
            while read JAR
            do
              if [ ! -z "$CP" ]; then
                CP=${CP}':'
              fi
              CP=${CP}${JAR}
            done
            echo $CP
          )
        }
        func
        

        【讨论】:

        • 这真的不是特别有用,你所做的只是在函数退出之前回显。
        【解决方案4】:

        这是另一种解决方案,它完全避免产生子外壳。关键是将循环输入捕获到一个变量中(在我的示例中称为“JARS”),然后使用 将此变量重定向到循环中

        JARS=$(ls -1)
        
        while read JAR
        do
                if [ ! -z "$CP" ]; then
                        CP=${CP}':'
                fi
                CP=${CP}${JAR}
        done <<EOF
        $JARS
        EOF
        
        echo $CP
        

        【讨论】:

        • 评估ls 的输出总是有问题的,如果路径包含空白等。
        【解决方案5】:

        这些答案似乎都没有真正正确地返回值,用一个非常简单的例程回显答案就可以了,但是说你想要脚本的输出,这是没用的。我没有最好的答案,但我也没有太多时间去弄清楚,所以我只是建议将你想要的内容准确地输出到临时文件并阅读它(很惊讶它没有迄今为止提到的):

        #!/bin/bash
        CP="AAA"
        func() {
          ls -1 | (
            while read JAR
            do
              if [ ! -z "$CP" ]; then
                CP=${CP}':'
              fi
              CP=${CP}${JAR}
            done
            echo "$CP" > /tmp/cp-value-file
          )
        }
        
        func
        CP=$(cat /tmp/cp-value-file)
        echo $CP
        

        缺点:在某些情况下,每次循环迭代都需要写入磁盘。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-31
          • 2012-07-30
          • 1970-01-01
          • 1970-01-01
          • 2023-03-21
          • 2019-04-30
          • 2018-03-19
          相关资源
          最近更新 更多