Bash for loop with wildcards and hidden files
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 g开发者_开发百科et 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.
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
.
If you want hidden and non hidden, set dotglob (bash)
#!/bin/bash
shopt -s dotglob
for file in *
do
echo "$file"
done
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.
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.
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.
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}
精彩评论