2

Given a folder (that my script get the of this folder as argument) , how can I creates array that will contain the names of all the files in this folder (and the files that exists at any folder in this folder and the other folder - recursively)?

I tried to do it like that :

#!/bin/bash

function get_all_the_files {
for i in "${1}"/*; do
         if [ -d "$i" ]; then 
            get_all_the_files ${1}
         else
            if [ -f "${i}" ]; then
                arrayNamesOfAllTheFiles=(${arrayNamesOfAllTheFiles[@]} "${i}")
            fi
         fi
done
}

arrayNamesOfAllTheFiles=()

get_all_the_files folder

declare -p arrayNamesOfAllTheFiles

But it's not working. What is the problem and how can I fix it?

Software_t
  • 576
  • 1
  • 4
  • 13
  • The way you append to your array splits existing filenames with spaces. It should either use quotes around the array expansion, `arr=("${arr[@]}" "$i")`, or (easier) append with the `+=` operator: `arr+=("$i")`. – Benjamin W. Jul 05 '18 at 13:20
  • And *how* is it not working? What happens? Can you show an example input directory structure and the expected output? – Benjamin W. Jul 05 '18 at 13:21

2 Answers2

4

To stick with your design (looping on the files and inserting only the regular files), populating the array at each step, but have Bash perform the recursion via the glob, you can use the following:

# the globstar shell option enables the ** glob pattern for recursion
shopt -s globstar

# the nullglob shell option makes non-matching globs expand to nothing (recommended)
shopt -s nullglob

array=()

for file in /path/to/folder/**; do
    if [[ ! -h $file && -f $file ]]; then
        array+=( "$file" )
    fi
done

With the test [[ ! -h $file && -f $file ]] we test that the file is not a symbolic link and a regular file (without testing that the file is not a symbolic link, you would also have the symbolic links that resolve to a regular file).

You also learned about the array+=( "stuff" ) pattern to append to an array, instead of array=( "${array[@]}" "stuff" ).


Another possibility (with Bash ≥ 4.4 where the -d option of mapfile is implemented) and with GNU find (that supports the -print0 predicate):

mapfile -d '' array < <(find /path/to/folder -type f -print0)
gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
2

You almost had it right. There is a small typo in the recursive call:

    if [ -d "$i" ]; then 
        get_all_the_files ${1}
    else

should be

    if [ -d "$i" ]; then 
        get_all_the_files ${i}
    else

I will add that use of arrays like this in bash is very unidiomatic. If you are trying to work with recursive trees of files, its more usual to use tools like find and xargs.

find . -type f -print0 | xargs -0 command-or-script-to-run-on-each-file
Jon
  • 3,573
  • 2
  • 17
  • 24
  • This breaks if any filenames have blanks in them as there is word splitting before the array elements are assigned. – Benjamin W. Jul 05 '18 at 13:15
  • @BenjaminW. Absolutely. I'll remove the `($(find ...))` as it's never a good idea. – Jon Jul 05 '18 at 13:19