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?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
stack smasher
  • 273
  • 1
  • 2
  • 6

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
  • 46,064
  • 19
  • 123
  • 136
  • 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