Variables value gets lost in subshell

前端 未结 5 1268
忘了有多久
忘了有多久 2020-12-21 09:57

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 re

相关标签:
5条回答
  • 2020-12-21 10:19

    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:

    JARS=$(ls -1)
    
    while read JAR
    do
            if [ ! -z "$CP" ]; then
                    CP=${CP}':'
            fi
            CP=${CP}${JAR}
    done <<EOF
    $JARS
    EOF
    
    echo $CP
    
    0 讨论(0)
  • 2020-12-21 10:21

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

    #!/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
    
    0 讨论(0)
  • 2020-12-21 10:27

    You might find using find a bit more versatile.

    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- )
    
    0 讨论(0)
  • 2020-12-21 10:29

    The issue here is that using while in 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:

    for JAR in *; do
        # Your stuff
    done
    

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

    This also shows you ways to avoid the subshell.

    0 讨论(0)
  • 2020-12-21 10:30

    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.

    0 讨论(0)
提交回复
热议问题