2

I am having some issues with local variables after exiting a loop. The variable max ends up with the value 0, despite the code below:

max=0
cat tmp|while read line
do
temp=$(echo $line|tr -d "\n"|wc -c)
if [ $temp -gt $max ];then

max=$temp
echo $max
fi
done
echo -n tmp $max

cat tmp
12345
123456

And this is the output I receive:

5
6
 tmp 0

I don't understand why max is 0 after exiting the loop, while inside the loop it finds the correct values.

1

5 Answers 5

13

A pipe starts a new subshell, with its own environment and variable space. Use < tmp at the end of the loop instead.

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

1 Comment

yes you right I fix it and now it is work, but I am not sure that pipe open new subshel whith variables ,as I understand it just an input buffer for new commands
3
max=0
while read line
do
    temp=$(echo $line|tr -d "\n"|wc -c)
    if [ $temp -gt $max ]
    then 
        max=$temp
        echo $max
    fi
done <tmp
echo -n tmp $max

Comments

3

According to the bash man page each command in a pipeline is executed in a subshell. That is, your while loop runs in a subshell and only the value of the variable max in that subshell is modified.

Variables of subshells are not propagated back to the calling shell, which is running the echo command and thus still sees the initial zero value.

If you run the echo in the same subshell (note the curly braces) it will work:

max=0
cat tmp|{
    while read line
    do
        temp=$(echo $line|tr -d "\n"|wc -c)
        if [ $temp -gt $max ];then
            max=$temp
        fi
    done
    echo -n tmp $max
}

If you need the value for further calculations in the outer shell, you would need to use command substitution like this:

max=0
max=$(cat tmp|{
    while read line
    do
        temp=$(echo $line|tr -d "\n"|wc -c)
        if [ $temp -gt $max ];then
            max=$temp
        fi
    done
    echo -n $max
})
echo tmp $max

Comments

1

The pipe before your while is putting everything inside the loop into a separate shell, and thus a separate identifier context (essentially a new environment).

Redirecting the tmp file into the while loop via < will keep your loop and variables all in the same execution context.

while read line
do
    # your loop stuff 
done < tmp

Comments

0

Here's a one liner in awk.

$ awk 'length>t{t=length}END{print t}' file
6

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.