Doubt array of bash

1

I was trying to do the following:    Make a script that adds to an array all the files in the / home directory whose termination is .doc
MY SOLUTION:

 vector=()  
 guardar=0  
 for i in 'find /home -name *.doc'; do       
      vector[$guardar]=$i        
     let guardar=guardar+1  
 done  

Is it well done? Thanks for helping me

    
asked by Janzek 01.11.2018 в 22:44
source

1 answer

3

The biggest problem with this code is this part:

for i in 'find /home -name *.doc'

You probably think that the variable i takes the value of each line from the output of the find command, but this is not the case. Actually the following happens:

  • The find command is executed.
  • The output of the command suffers the effect known as word splitting .
  • The result of the previous step suffers the effect known as filename expansion .
  • The resulting elements are used by the for command to be assigned to the variable i in their corresponding iteration.
  • Put another way, the process will fail if any of the file names contain characters that cause filename expansion or word splitting . .

    That is, if the output of find were this:

    ./archivo 1.doc
    ./archivo 2.doc
    ./archivo *.doc
    

    The content of the array would be this (each line is an element of the array):

    ./archivo
    1.doc
    ./archivo
    2.doc
    ./archivo
    archivo 1.doc
    archivo 2.doc
    archivo *.doc
    

    On the other hand, it is not necessary to manually manage the array indexes. You can use the arreglo+=(elemento) syntax for Bash to do that work for you.

    That said, I can think of at least two methods to deal with this situation.

    Method 1: Filename expansion

    This is the native method, but it is not as fast or as powerful as find :

    for archivo in "${HOME}"/*.doc; do
      arreglo+=( "${archivo}" )
    done
    
    shopt -s dotglob globstar
    
    for archivo in "${HOME}"/**/*.doc; do
      arreglo+=( "${archivo}" )
    done
    

    The first searches for files within the ${HOME} directory that match the *.doc pattern. The second does the same but recursively, including hidden directories.

    Method 2: mapfile + process substitution

    Useful if you prefer to use find but avoiding the effects of filename expansion , word splitting and the use of for :

    mapfile -t arreglo < <(find "${HOME}" -name '*.doc')
    

    With GNU find you could even use the -print0 option to avoid problems with line breaks in the file names:

    mapfile -d '' -t arreglo < <(find "${HOME}" -name '*.doc' -print0)
    
        
    answered by 02.11.2018 в 04:56