17

I need to iterate through every file inside a directory. One common way I saw was using the for loop that begins with for file in *; do. However, I realized that it does not include hidden files (files that begin with a "."). The other obvious way is then do something like

for file in `ls -a`; do

However, iterating over ls is a bad idea because spaces in file names mess everything up. What would be the proper way to iterate through a directory and also get all the hidden files?

1 Answers1

32

You just need to create a list of glob matching files, separated by space:

for file in .* *; do echo "$file"; done

Edit

The above one can rewrite in different form using brace expansion

 for file in {.*,*}; do echo "$file"; done

or even shorter: for file in {.,}*; do echo "$file"; done

Adding the path for selected files:

 for file in /path/{..?,.[!.],}*; do echo "$file"; done

Adding path for selected files:

 for file in /path/{.,}*; do echo "$file"; done

If you want to be sophisticated and remove from the list usually unneeded . and .. just change {.,}* to {..?,.[!.],}*.

For completeness it is worth to mention that one can also set dotglob to match dot-files with pure *.

shopt -s dotglob

In zsh one needs additionally set nullglob to prevent the error in case of no-matches:

setopt nullglob

or, alternatively add glob qualifier N to the pattern:

for file in /path/{.,}*(N); do echo "$file"; done
jimmij
  • 47,140
  • Thanks a lot! So if I want to iterate through any directory, I just put the directory name in front of each of the items right? like for file in dir/.* dir/*; do – stack smasher Oct 16 '14 at 20:46
  • 3
    It's not so easy. .* matches . and .. (except in zsh). * stays * if there is no matching file. shopt -s gotglob is only in bash. – Gilles 'SO- stop being evil' Oct 16 '14 at 23:23
  • I am getting zsh: no matches found: .* when I run the command(s) in this answer. Why would this happen? ls on the directory shows the files. – Niyaz Oct 10 '17 at 18:57
  • @Niyaz that's because zsh return error if some pattern no matches. To prevent that run setopt nullglob which will turn off this feature globally, or add qualifier (N) after the glob star, i.e.: for file in /path/{.,}*(N); do echo "$file"; done. – jimmij Oct 10 '17 at 22:13