views:

91

answers:

8

I want to loop over the files that begin with '.' in directory x (x might be any path):

$ for file in x/.*
> do
>     echo -n $file" "
> done
x/. x/.. x/..a x/.b

What is the best way to get rid of x/., and x/.. ?

+3  A: 

Use the pattern .{[^.]*,.?*}, which means any name that starts with . followed by a character that isn’t a ., or a name that starts with .. followed by a character.

Also you should write "$file" in quotes so names with spaces don’t get broken apart.

jleedev
This will fail if for some strange reason there is a file that starts with two periods.
Ignacio Vazquez-Abrams
I've changed the question a bit, this time there is a file that begins with ..
TheOsp
@Ignacio D'oh! Fixed.
jleedev
You'll want to use the new pattern with `nullglob` in case there's no files that match `..?*`.
Ignacio Vazquez-Abrams
A: 
for file in x/.*; do echo  "$file "; done | grep -v "x/\.\{1,2\} $" | tr -d '\n'

The space after $file and before $ in grep are important. It makes sure that you have spaces between the listings and that everything is not scrunched up.

or more generically

for file in somedir/.*; do echo  "$file "; done | grep -v "\w/\.\{1,2\} $" | tr -d '\n'
Vivin Paliath
A: 

Use ls -A on Mac OS X. Check the man page for your implementation for local options. This command

ls -A | grep '^\.'

Gave me the list you're looking for.

Carl Norum
I prefer not to use lshttp://mywiki.wooledge.org/ParsingLs
TheOsp
`ls -A` is standard.
jleedev
+1  A: 

As another pointed out, ls -A excludes . and .. from the listing, not sure how standard it is.

You can also use find:

find .  -mindepth 1 -maxdepth 1 -name '.*'
leonbloy
`ls -A` is standard, but the solution with `find` is better (especially if you pair it with `xargs` or `-exec`).
jleedev
+5  A: 

with bash, you can use GLOBIGNORE

$ ls -1tra
..
.test1
.test
test
.

$ for i in .*; do echo $i;done
.
..
.test
.test1

$ GLOBIGNORE=".:.."
$ for i in .*; do echo $i;done
.test
.test1
ghostdog74
Great :) thank you
TheOsp
This is probably the easiest for a script - for something easier to use here and there on the command-line, see my answer. `extglob` is pretty handy.
Jefromi
To really answer the question it has to be: GLOBIGNORE="*/.:*/.." (to work outside the current $PWD)
TheOsp
+1  A: 

A solution with only globbing, so you don't have to trouble with command substitution and quoting:

.!(.|)

This requires the extglob shell option to be set:

shopt -s extglob

This is probably obvious, but the !() construct means anything besides one of the patterns listed (delimited by |).

Jefromi
Thank you, depends on the situation, I'll probably use this one too.--If only I could select two accepted answers...
TheOsp
A: 

(1) Use 2 patterns: $ echo x/.??* x/.[^.] - there are other combinations. If using a different one, make sure it would catch "..." and ".a"

(2) Use GLOBIGNORE and exclude the 2 entries: $ GLOBIGNORE='/.:/..'; echo x/.*

(3) Use dotglob with GLOBIGNORE. This will automatically exclude . and .., but now you have to exclude "all the rest": $ shopt -s dotglob; GLOBIGNORE='/[^.]'; echo x/*

tm
A: 

for file in x/.{[^.],.?}*

This will match e.g. .a .zoo.17 ... ..0 ..hello

but will not match . .. files-not-starting-with-dot

breaking it down...

the {a,b} does an alternation, first matching a, then matching b. So we could also write the above like so:

for file in x/.[^.]* x/..?*

So let's examine the first: .[^.]* The [^.] is an inverted character class -- without the carat ^ it would match only a dot; the ^ inverts it so it will match any character except dot. After that is a star, which will match 0 or more characters of any sort So this pattern .[^.]* will match files with names that - start with . - are at least two characters long - the second character is not . From the above examples, it matches: .a .zoo.17

Now let's examine the second: ..?* The ? matches any character (but not 0 characters). We're familiar with the star. So this pattern ..?* will match files with names that - start with .. - are at least three characters long From the above examples, it matches: ... ..0 ..hello

Because of the way the alternation works, the files in the first group will all be matched first -- they will not be collated with the files in the second group.

David Emerson