The bash shell can recurse into directories with its special ** globbing pattern. The ** pattern matches like *, but also reaches across / in pathnames:
shopt -s globstar nullglob dotglob
for dirpath in ./**/; do
printf '%s\n' "$dirpath"
# whatever other code needs to be run on "$dirpath"
done
I'm enabling globstar to get access to **, and I'm also enabling nullglob and dotglob to be able to skip the loop entirely if the pattern does not match anything , and to also see hidden files.
The pattern ./**/ would match any directory in or below the current directory, just like ./*/ would match any directory in the current directory.
Use ./**/* or ./** to list all types of files.
You can also do this portably with find:
find . -type d -exec sh -c '
for dirpath do
printf "%s\n" "$dirpath"
# whatever other code needs to be run on "$dirpath"
done' sh {} +
Here, find feeds the loop in the sh -c script with pathnames of directories.
The only difference that you will see when running these two examples is that the first example (the bash loop with **) will resolve symbolic links to directories, while find will not resolve symbolic link to directories.
If all you want is to list directories, then the find example may be shortened significantly into
find . -type d -print
Use -type f in place of -type d to see only regular files, and delete the -type test completely to see all types of files.
You could obviously also use ls to get such a list, but I don't really see much point in it as you can't do anything but look at the output from ls anyway.
shopt -s globstar dotglob
ls -1d ./**
Note that this command runs the risk of triggering an "argument list too long" error if the list of pathnames that the pattern expands to is too long. None of the other commands in this answer has that issue.
Also note that it isn't really ls that does any recursing here, it's the shell expanding the ./** pattern that recurses, and it does that to create the list of arguments for ls before ls is even invoked.