Is there any zsh glob that will find directories that are either empty or that only contain a .DS_Store
file?
I know that the (/^F)
glob flag combo will find empty directories, but I also want to include directories that contain only a .DS_Store
file but that contain no other nodes (files, directories, etc.).
For my purposes, if I cannot filter out specifically .DS_Store
, filtering out either all hidden files (.*(.)
) or all hidden nodes (.*
) will suffice.
Not simple, but we could do:
setopt extendedglob # for '~' and '#q' in the `[[ … ]]' form
setopt globstarshort # shortcut for '**/*' to '**'
print -rC1 -- **(DN/^F,/e['[[ -z $REPLY/*~*/.DS_Store(#qoNDNY1) ]]'])
lists empty directories or directories in which any file does not exist other than .DS_Store (in other words: only .DS_Store exits).
**(…)
:
GLOB_STAR_SHORT
shortcut for **/*
.
*(…)
: Glob
qualifiers
specify which filenames that otherwise match the given pattern will
be inserted in the argument list.
D
: set
GLOB_DOTS
,
include dotfiles,dirs.
N
: set
NULL_GLOB
,
don't signal error if pattern does not match. (Not required for
particularly testing/experimenting.)
/^F
: zsh idiom for empty directories.
,
: OR
/e[…]
: directories AND e
string qualifier that is directories
which satisfy the zsh code string that is …
.
[[ -z … ]]
: will describe no file exists other than .DS_Store
using glob patterns.
$REPLY
: during execution e[…]
, the filename currently being
tested in this case directoryname will be passed by zsh.
*~*/.DS_Store
: X~Y
means match anything that matches the pattern
X
but does not match Y
. So, it will expand anything other than
.DS_Store
.
#q
: globbing performed in the [[ -z … ]]
form.
oN
: no sort.
D
:
GLOB_DOTS
again.
N
: set
NULL_GLOB
,
let zsh not signal error while processing e[…]
.
Y1
: short-circuit, only the first 1 match will be considered is
enough.
setopt extendedglob globstarshort
rm -rf tester
mkdir tester
cd tester
mkdir empty dsstore-only more-dotfiles more
touch dsstore-only/.DS_Store more-dotfiles/{.DS_Store,.DS_Store.old} more/{.DS_Store,more}
mkdir child
cp -a ^child child
tree -a
#>> .
#>> ├── child
#>> │ ├── dsstore-only
#>> │ │ └── .DS_Store
#>> │ ├── empty
#>> │ ├── more
#>> │ │ ├── .DS_Store
#>> │ │ └── more
#>> │ └── more-dotfiles
#>> │ ├── .DS_Store
#>> │ └── .DS_Store.old
#>> ├── dsstore-only
#>> │ └── .DS_Store
#>> ├── empty
#>> ├── more
#>> │ ├── .DS_Store
#>> │ └── more
#>> └── more-dotfiles
#>> ├── .DS_Store
#>> └── .DS_Store.old
#>>
#>>10 directories, 10 files
print -rC1 -- **(DN/^F,/e['[[ -z $REPLY/*~*/.DS_Store(#qoNDNY1) ]]'])
#>> child/dsstore-only
#>> child/empty
#>> dsstore-only
#>> empty
Note: some references:
Glob Qualifires:
...
More than one of these lists can be combined, separated by commas. The whole list matches if at least one of the sublists matches (they are `or'ed, the qualifiers in the sublists are `and'ed). Some qualifiers,
Conditional Expressions:
...
Filename generation is not performed on any form of argument to conditions. However, it can be forced in any case where normal shell expansion is valid and when the option EXTENDED_GLOB is in effect by using an explicit glob qualifier of the form (#q) at the end of the string.