Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm running zsh on Linux under setopt extended_glob ksh_glob glob_dots. I'm looking for something easy to type on the command line, with no portability requirements. I'm looking at a source code tree, with no “weird” file names (e.g. no \ in file names, no file name beginning with -).

Either of the following commands print the list of subdirectories of the current directory recursively:

find -type d
print -l **/*/

This is actually an svn checkout:

$ find -type d
./.deps
./.svn
./.svn/text-base
./.svn/prop-base
./.svn/tmp
./.svn/tmp/text-base
./.svn/tmp/prop-base
./.svn/tmp/props
./.svn/props
./lib/.svn
./lib/.svn/text-base
./lib/.svn/prop-base
./lib/.svn/tmp
./lib/.svn/tmp/text-base
./lib/.svn/tmp/prop-base
./lib/.svn/tmp/props
./src/.svn
./src/.svn/text-base
./src/.svn/prop-base
./src/.svn/tmp
./src/.svn/tmp/text-base
./src/.svn/tmp/prop-base
./src/.svn/tmp/props

I want to exclude the .svn directories and their subdirectories which are present in every directory. It's easy with find:

find -type d -name .svn -prune -o -print

Can I do this with a short zsh glob? Ignoring dot files comes close (I need to do it explicitly because I have glob_dots set):

print -l **/*(/^D)

But this isn't satisfactory because it hides the .deps directory, which I do want to see. I can filter out the paths containing .svn:

print -l **/*~(*/|).svn(|/*)(/)

But that's barely shorter than find (so what am I using zsh for?). I can shorten it to print -l **/*~*.svn*(/), but that also filters out directories called hello.svn. Furthermore, zsh traverses the .svn directories, which is a bit slow on NFS or Cygwin.

Is there a convenient (as in easy to type) way to exclude a specific directory name (or even better: an arbitrary pattern) in a recursive glob?

share|improve this question
    
Why would you spend some time finding out whether your files have or have not dashes or backslashes (and let other readers find out by themselves when they can't guarantee that) instead of just write the bulletproof right thing like printf '%s\n' **/* or print -rl -- **/*? –  Stéphane Chazelas Apr 10 '13 at 6:59
    
@StephaneChazelas In a script, sure. But on the command line, saving 4 characters is worth it. In my real-world situation, I didn't need to find out about file names, I already knew (build trees tend to have tame file names). –  Gilles Apr 10 '13 at 8:51
add comment

2 Answers

up vote 11 down vote accepted

Zsh's extended glob operators support matching over / (unlike ksh's, even in zsh's implementation). Zsh's **/ is a shortcut for (*/)# (*/ repeated 0 or more times). So all I need to do is replace that * by ^.svn (anything but .svn).

print -l (^.svn/)#

Neat!

share|improve this answer
add comment

While ksh93 globbing is nowhere near zsh's even with the globstar option, in ksh93, it can be achieved with:

set -o globstar
FIGNORE='@(.|..|.svn)'
printf '%s\n' **/
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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