bashshell

How do you recursively specify all non-directory files in a directory?


Suppose I had a directory, e.g. animals, structured like:

animals
├── ant.pdf
├── cat
│   ├── ragdoll.txt
│   └── sphinx.png
├── dog
│   ├── labrador.jpg
│   └── pitbull.mp3
├── rat
│   └── labrat.gif
└── shark.java

And I wanted a Bash array consisting of "ant.pdf", "ragdoll.txt", "sphinx.png", "labrador.jpg", "pitbull.mp3", "labrat.gif", "shark.java", i.e. all the end nodes of this tree (not including any empty subdirectories). I would want to follow any subdirectories recursively with no maximum depth, or in practice no reasonable maximum depth i.e. one so high that it wouldn't be expected to be reached in a user's files.

What would be the best way to do this? I've got

files=(animals/*)

(replacing animals with whatever the directory is, of course)

which would give me an array of "ant.pdf", "cat", "dog", "rat", "shark.java", but not "ragdoll.txt" etc from the subdirectories, and I also don't want the subdirectories themselves to be in the array.


Solution

  • The only character that cannot appear in a file name is NUL (ASCII code 0), plus / in base file names. So to do what you want, including if file names contain newline characters, you must use one or the other as separator. Demo:

    mkdir -p tests/a; cd tests; touch $'a/b\nb'
    readarray -t files < <(find . -type f)
    printf '>>> |%s|\n' "${files[@]}"
    >>> |./a/b|
    >>> |b|
    

    If you want to store the path of files you must use NUL as separator (-d '' option of readarray and -print0 action of find):

    readarray -d '' -t files < <(find . -type f -print0)
    printf '>>> |%s|\n' "${files[@]}"
    >>> |./a/b
    b|
    

    If you want to store only the base names you must use NUL or / as separator:

    readarray -d '' -t files < <(find . -type f -printf "%f\0")
    printf '>>> |%s|\n' "${files[@]}"
    >>> |b
    b|
    

    Or:

    readarray -d '/' -t files < <(find . -type f -printf "%f/")
    printf '>>> |%s|\n' "${files[@]}"
    >>> |b
    b|