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?
Best Answer
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
).Neat!