N00b
N00b

Reputation: 148

Why returning value from function is causing operational disturbance on this code?

I made little piece of code to describe my problem.

#!/bin/bash

function writeToFile(){
    echo "$1" >> file.txt
}

function checkLetters(){
    letters_array+=( $1 )
    count=0
    for letter in ${letters_array[*]}
    do
        if [[ "$1" == "$letter" ]]
        then
            count=$((count+1))  
        fi
    done
    value=1
    if [[ $count -eq $value ]] 
    then                    
        writeToFile "$1" 
    fi
    echo "return"
}

letters=( a b c d e )
for i in {1..2}
do
    for letter in ${letters[*]}
    do
        checkLetters $letter
    done
done
file="/mnt/file.txt"
while IFS= read -r line
do
    printf "$line\n"
done <"$file"

`> file.txt`

So code is writing letters to file if there is not yet same letter in file. If code is working properly, in file there must be letters a,b,c,d,e and there is if I use code like above. But I need return value from function so I change

checkLetters $letter

to this:

return_value=$(checkLetters $letter)

Now my file is containing a,b,c,d,e,a,b... Why? Why returning value is causing that and how to get that work properly?

Upvotes: 0

Views: 38

Answers (1)

marcolz
marcolz

Reputation: 2970

Because the command (in this case the function checkLetters) is executed in a subshell, which inherits the existing letters_array but only updates its local copy.

Form the bash(1) manual page:

Bash performs the expansion by executing command in a subshell environment and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting. The command substitution $(cat file) can be replaced by the equivalent but faster $(< file).

So exactly the same would happen if you would use

( checkLetters $letter; )

Example:

arr=( )
function test() {
    arr+=( $1 )
    echo "in test ($1): ${arr[*]}"
}

test 1; test 2;
echo ${arr[*]}

echo "substitution: $(test 3)"
echo "After command substitution: ${arr[*]}"

( test 5; echo "in subshell: ${arr[*]}"; )
echo "after subshell: ${arr[*]}"

results in:

in test (1): 1
in test (2): 1 2
1 2
substitution: in test (3): 1 2 3
After command substitution: 1 2
in test (5): 1 2 5
in subshell: 1 2 5
after subshell: 1 2

Upvotes: 1

Related Questions