3

In my bash script I use while read loop and a helper function fv():

fv() {
    case "$1" in
    out) echo $VAR
    ;;
    *  ) VAR="$VAR $1"
    ;; 
    esac
}

cat "$1" | while read line
    do
        ...some processings...
        fv some-str-value
    done

echo "`fv out`"

in a hope that I can distil value from while read loop in a variable accessible in rest of the script. But above snippet is no good, as I get no output.

Is there easy way to solve this - output string from this loop in a variable that would be accessible in rest of the script - without reformatting my script?

3 Answers 3

5

As no one has explained to you why your code didn't work, I will.

When you use cat "$1" |, you are making that loop execute in a subshell. The VAR variable used in that subshell starts as a copy of VAR from the main script, and any changes to it are limited to that copy (the subshell's scope), they don't affect the script's original VAR. By removing the useless use of cat, you remove the pipeline and so the loop is executed in the main shell, so it can (and does) alter the correct copy of VAR.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your explanation. First I was surprised as why my variables inside this loop are reset. I found out, here on SO, that it's because of subshell execution. Then I thought to create this helper function and create variables there instead in a loop, from which I will only output values, as obvious from my posted snippet. What it's still not clear to me is why this outside function fv(), where I create the variable, is influenced by this subsheel loop, but I imagine it's drowned in subshell as it's called from there.
Functions are executed within the current shell, not a subshell. That means that not only can they see the environment at the point where they are called, they can alter it there.
4

Replace your while loop by while read line ; do ... ; done < $1:

#!/bin/bash

function fv
{
    case "$1" in
    out) echo $VAR
    ;;
    *  ) VAR="$VAR $1"
    ;; 
    esac
}

while read line
    do
        fv "$line\n"
    done < "$1"

echo "$(fv out)"

Comments

1

Stop piping to read.

done < "$1"

1 Comment

Sorry, but I'm new to Linux and can't decrypt your message. Can you expand it a bit?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.