bash 变量值在子shell中丢失

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3085518/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 22:14:09  来源:igfitidea点击:

Variables value gets lost in subshell

bashunixscripting

提问by stacker

This bash script concatenates the names for jar files to a classpath (variable CP), in the while loop the value is correct but is lost in the subshell as descibed in this related question Bash variable scope

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

#!/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

My question is, since I can't figure out which element will be the last one, how can the value be saved.

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

Do I actually have to save the current value (repeatedly in the loop) to a file?

我实际上是否必须将当前值(在循环中反复)保存到文件中?

EDIT:

编辑:

A colleague came up with this command sequence which works well

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

ls | xargs echo|tr ' ' :

回答by Daenyth

The issue here is that using whilein a pipeline creates a subshell, and a subshell cannot affect its parent. You can get around this in a few ways. For what you are doing now, this will suffice:

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

for JAR in *; do
    # Your stuff
done

Another thing to note is that you shouldn't rely on parsing ls

另一件需要注意的是,你不应该依赖解析ls

Thisalso shows you ways to avoid the subshell.

也向您展示了避免子shell的方法。

回答by stacker

You might find using find a bit more versatile.

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

For example:

例如:

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

Of course set of find options is dependant on what you need/want.

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

This one is closer to what you had previously:

这个更接近你之前的情况:

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

回答by Mark Edgar

Implicit subshells are confusing; always make them explicit by using parentheses. To solve your problem, just move the echo inside the subshell.

隐式子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

回答by Andrew Davidson

Here is another solution, which avoid the spawning of a subshell altogether. The key is to capture the loop input into a variable (in my example called "JARS") and then redirect this variable into the loop using << EOF:

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

JARS=$(ls -1)

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

echo $CP

回答by Mike Q

None of these answers seem to get into actually returning the value properly, echoing out the answer is fine with a very simple routine, but say you want output of the script in action, this is useless. I don't have the best answer but I don't have much time to figure it out either, so I'm just going to suggest to output exactly what you want to a temp file and read that (surprised it hasn't been mentioned to date) :

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

#!/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

Downside: will in some cases need to write to the disk every iteration of the loop.

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