In bash I often use for-loops such as the following

for file in *.type; do 
  sommecommand "$file"; 

to perform an operation for all files matching *.type. If no file with this ending is found in the working directories the asterisk is not expanded and usually I will get an error message saying that somecommand didn't find the file. I can immediately think of several ways to avoid this error. But adding a conditional does not seem to be very elegant. Is there a short and clean way to achieve this?


Yes, run the following command :

shopt -s nullglob

it will nullify the match and no error will be triggered.

  • if you want this behaviour by default, add the command in your ~/.bashrc
  • if you want to detect a null glob in POSIX shell, try

    for i in *.txt; do
      [ "$i" = '*.txt' ] && [ ! -e '*.txt' ] && continue

See http://mywiki.wooledge.org/NullGlob

| improve this answer | |
  • 1
    Note that it is actually possible to have a file called *.txt. It would be worth checking if the file exists. – Chris Down Nov 18 '12 at 19:17
  • post edited accordingly. – Gilles Quenot Nov 18 '12 at 19:20
  • @ChrisDown Note that the same comment as on your answer applies here (with potentially more severe consequences because of the break instead of continue). – Stéphane Chazelas Nov 19 '12 at 10:59

In bash you can use shopt -s nullglob to expand to an empty array if there are no matches.

In POSIX shells without nullglob, you can avoid this problem by checking that the filename being passed actually exists by having [ -e "$file" ] || [ -L "$file" ] || continue as the first part of your for loop.

| improve this answer | |
  • 1
    Note that it wouldn't be strictly equivalent since [ -e would return false for inaccessible files or files that are symlinks to inaccessible or unexisting files. – Stéphane Chazelas Nov 18 '12 at 19:14
  • @StephaneChazelas, let the points about symlinks be acknowledged. But what do you have in mind by "inaccessible files"? Even if I chmod 0 the_file, [ -e the_file ] still evaluates true, so it must be something else. – dubiousjim Nov 18 '12 at 21:34
  • 1
    submitted edit to handle broken symlinks. hope that's ok. – dubiousjim Nov 18 '12 at 21:38
  • 2
    @dubiousjim, mkdir -p x/{a,b} && chmod 444 x && echo x/* && [ -e x/a ]. x/a is inaccessible but as x is readable x/* will expand. – Stéphane Chazelas Nov 19 '12 at 9:51
  • @StephaneChazelas, great, thanks for explaining. – dubiousjim Nov 19 '12 at 16:22

The usual technique for shells that don't have a nullglob option is

set -- [*].type *.type
case $1$2 in
  '[*].type*.type') shift 2;;
  *) shift
for file do
  cmd  -- "$file"

The extra [*].type is to cover the case where there's one file called *.type in the current directory.

Now, if you want to include dot files, that becomes more complicated.

I beleive that technique was coined by Laura Fairhead on usenet a few years ago.

| improve this answer | |

find . -name '*.type' -maxdepth 0 -exec somecommand "{}" ";"

This removes the for loop and the shell's globbing from the equation entirely. find will execute the -exec command once per match, and if there are no matches, it will never be executed. The -maxdepth 0 instructs find to not recurse into subdirectories of the named path-argument (., in this case).

The downside is that it involves another application, albeit one that is present on virtually every Linux system out there (and probably most Unixes as well).

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.