Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to loop over directories in Linux?

Tags:

linux

bash

People also ask

How do you loop a directory in Linux?

We use a standard wildcard glob pattern '*' which matches all files. By adding a '/' afterward, we'll match only directories. Then, we assign each directory to the value of a variable dir. In our simple example, we then execute the echo command between do and done to simply output the value of the variable dir.

How do I traverse a directory in Unix?

This can be easily achieved by mixing find , xargs , sed (or other file modification command). This will filter all files with file extension . properties . The xargs command will feed the file path generated by find command into the sed command.


All answers so far use find, so here's one with just the shell. No need for external tools in your case:

for dir in /tmp/*/     # list directories in the form "/tmp/dirname/"
do
    dir=${dir%*/}      # remove the trailing "/"
    echo "${dir##*/}"    # print everything after the final "/"
done

cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n'

A short explanation:

  • find finds files (quite obviously)

  • . is the current directory, which after the cd is /tmp (IMHO this is more flexible than having /tmp directly in the find command. You have only one place, the cd, to change, if you want more actions to take place in this folder)

  • -maxdepth 1 and -mindepth 1 make sure that find only looks in the current directory and doesn't include . itself in the result

  • -type d looks only for directories

  • -printf '%f\n prints only the found folder's name (plus a newline) for each hit.

Et voilà!


You can loop through all directories including hidden directrories (beginning with a dot) with:

for file in */ .*/ ; do echo "$file is a directory"; done

note: using the list */ .*/ works in zsh only if there exist at least one hidden directory in the folder. In bash it will show also . and ..


Another possibility for bash to include hidden directories would be to use:

shopt -s dotglob;
for file in */ ; do echo "$file is a directory"; done

If you want to exclude symlinks:

for file in */ ; do 
  if [[ -d "$file" && ! -L "$file" ]]; then
    echo "$file is a directory"; 
  fi; 
done

To output only the trailing directory name (A,B,C as questioned) in each solution use this within the loops:

file="${file%/}"     # strip trailing slash
file="${file##*/}"   # strip path and leading slash
echo "$file is the directoryname without slashes"

Example (this also works with directories which contains spaces):

mkdir /tmp/A /tmp/B /tmp/C "/tmp/ dir with spaces"
for file in /tmp/*/ ; do file="${file%/}"; echo "${file##*/}"; done

Works with directories which contains spaces

Inspired by Sorpigal

while IFS= read -d $'\0' -r file ; do 
    echo $file; ls $file ; 
done < <(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d -print0)

Original post (Does not work with spaces)

Inspired by Boldewyn: Example of loop with find command.

for D in $(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d) ; do
    echo $D ;
done

find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n"