33

Just witting a simple shell script and little confused:

Here is my script:

% for f in $FILES; do echo "Processing $f file.."; done

The Command:

ls -la | grep bash 

produces:

% ls -a | grep bash
.bash_from_cshrc
.bash_history
.bash_profile
.bashrc

When

FILES=".bash*"

I get the same results (different formatting) as ls -a. However when

FILES="*bash*"

I get this output:

Processing *bash* file..

This is not the expected output and not what I expect. Am I not allowed to have a wild card at the beginning of the file name? Is the . at the beginning of the file name "special" somehow?

Setting

FILES="bash*"

Also does not work.

7ochem
  • 2,183
  • 1
  • 34
  • 42
sixtyfootersdude
  • 25,859
  • 43
  • 145
  • 213

6 Answers6

64

The default globbing in bash does not include filenames starting with a . (aka hidden files).

You can change that with

shopt -s dotglob

$ ls -a
.  ..  .a  .b  .c  d  e  f
$ ls *
d  e  f
$ shopt -s dotglob
$ ls *
.a  .b  .c  d  e  f
$ 

To disable it again, run shopt -u dotglob.

fedorqui
  • 275,237
  • 103
  • 548
  • 598
nos
  • 223,662
  • 58
  • 417
  • 506
17

If you want hidden and non hidden, set dotglob (bash)

#!/bin/bash
shopt -s dotglob
for file in *
do
 echo "$file"
done
msrd0
  • 7,816
  • 9
  • 47
  • 82
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
11

FILES=".bash*" works because the hidden files name begin with a .

FILES="bash*" doesn't work because the hidden files name begin with a . not a b

FILES="*bash*" doesn't work because the * wildcard at the beginning of a string omits hidden files.

Lance Roberts
  • 22,383
  • 32
  • 112
  • 130
gregseth
  • 12,952
  • 15
  • 63
  • 96
  • 8
    So if I want to do it I should do FILES=".*bash*"? But what if I want hidden AND not hidden files? – sixtyfootersdude Jan 25 '10 at 21:42
  • This is slightly confused because the quotes prevent the wildcards from expanding at all. The expansion happens when you _use_ `$FILES`, unquoted. – tripleee Apr 21 '22 at 02:48
11

Yes, the . at the front is special, and normally won't be matched by a * wildcard, as documented in the bash man page (and common to most Unix shells):

When a pattern is used for pathname expansion, the character “.” at the start of a name or immediately following a slash must be matched explicitly, unless the shell option dotglob is set. When matching a pathname, the slash character must always be matched explicitly. In other cases, the “.” character is not treated specially.

alanc
  • 4,102
  • 21
  • 24
4

If you want to include hidden files, you can specify two wildcards; one for the hidden files, and another for the others.

for f in .[!.]* *; do
    echo "Processing $f file.."
done

The wildcard .* would expand to all the dot files, but that includes the parent directory, which you normally would want to exclude; so .[!.]* matches all files whose first character is a dot, but the second one isn't.

If you have other files with two leading dots, you need to specify a third wildcard to cover those but exclude the parent directory! Try ..?* which requires there to be at least one character after the second dot.

tripleee
  • 175,061
  • 34
  • 275
  • 318
1
for file in directory/{.[!.]*,*};do echo $file;done

Should echo either hidden files and normal file. Thanks to tripleee for the .[!.]* tip. The curly brackets permits a 'or' in the pattern matching. {pattern1,pattern2}

douardo
  • 697
  • 6
  • 6