Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append to an array variable from a pipeline command

I am writing a bash function to get all git repositories, but I have met a problem when I want to store all the git repository pathnames to the array patharray. Here is the code:

gitrepo() {
    local opt

    declare -a patharray
    locate -b '\.git' | \
        while read pathname
        do
            pathname="$(dirname ${pathname})"
            if [[ "${pathname}" != *.* ]]; then
            # Note: how to add an element to an existing Bash Array
                patharray=("${patharray[@]}" '\n' "${pathname}")
                # echo -e ${patharray[@]}
            fi
        done
    echo -e ${patharray[@]}
}

I want to save all the repository paths to the patharray array, but I can't get it outside the pipeline which is comprised of locate and while command.
But I can get the array in the pipeline command, the commented command # echo -e ${patharray[@]} works well if uncommented, so how can I solve the problem?

And I have tried the export command, however it seems that it can't pass the patharray to the pipeline.

like image 569
zhenguoli Avatar asked May 14 '16 16:05

zhenguoli


People also ask

How do you append an array to a variable?

To find it, you can search for “Append to array variable” action or go to “Built-in”: You won't probably see it in the main options, so you'll need to expand until you dine the “Variable” group. Pick “Variable.” Select the “append to string variable” action.

Can a script add additional elements to an array?

When you want to add an element to the end of your array, use push(). If you need to add an element to the beginning of your array, try unshift(). And you can add arrays together using concat().

How do you store the output of a command in an array?

The <(COMMAND) is called process substitution. It makes the output of the COMMAND appear like a file. Then, we redirect the file to standard input using the < FILE. Thus, the readarray command can read the output of the COMMAND and save it to our my_array.


1 Answers

Bash runs all commands of a pipeline in separate SubShells. When a subshell containing a while loop ends, all changes you made to the patharray variable are lost.

You can simply group the while loop and the echo statement together so they are both contained within the same subshell:

gitrepo() {
    local pathname dir
    local -a patharray

    locate -b '\.git' | {                      # the grouping begins here
        while read pathname; do
            pathname=$(dirname "$pathname")
            if [[ "$pathname" != *.* ]]; then
                patharray+=( "$pathname" )     # add the element to the array
            fi
        done
        printf "%s\n" "${patharray[@]}"        # all those quotes are needed
    }                                          # the grouping ends here
}

Alternately, you can structure your code to not need a pipe: use ProcessSubstitution ( Also see the Bash manual for details - man bash | less +/Process\ Substitution):

gitrepo() {
    local pathname dir
    local -a patharray

    while read pathname; do
        pathname=$(dirname "$pathname")
        if [[ "$pathname" != *.* ]]; then
            patharray+=( "$pathname" )     # add the element to the array
        fi
    done < <(locate -b '\.git')

    printf "%s\n" "${patharray[@]}"        # all those quotes are needed
}
like image 134
glenn jackman Avatar answered Sep 28 '22 09:09

glenn jackman