Есть ли какой-нибудь zsh glob, который найдет пустые каталоги или содержащие только файл .DS_Store
?
Я знаю, что комбинация флагов (/^F)
glob найдет пустые каталоги, но я также хочу включить каталоги, которые содержат только файл .DS_Store
, но не содержат других узлов (файлов, каталогов и т. д.).
Для моих целей, если я не могу отфильтровать конкретно .DS_Store
, достаточно отфильтровать все скрытые файлы (.*
).
Я пытаюсь использовать glob, чтобы сохранить его родным для zsh для обеспечения переносимости и производительности, и чтобы я мог научиться использовать более продвинутые функции zsh. К вашему сведению: у find
есть оператор -or
, поэтому два вызова find
можно объединить.
Кто бы ни голосовал за закрытие: почему?
С точки зрения производительности и портативности я бы сказал, используйте find. Использование -o (совместимо с POSIX) может довольно быстро усложниться, но это субъективно.
Это похоже на apple.stackexchange.com в частности, unix.stackexchange.com в целом или superuser.com в крайнем случае.
Суть этого вопроса не относится только к macOS. То же решение будет работать с zsh на любой платформе. В Stack Overflow более 6,1 тыс. вопросов по zsh, в Unix — более 3 тыс., в суперпользователе — более 1,4 тыс., а в Ask Different — более 400, поэтому я выбрал Stack Overflow.
Для всех «скрытых файлов» в дереве каталогов ниже каталога top
следует использовать top/**/.*(ND)
.
@user1934428 user1934428 Я хочу отфильтровать .DS_Store
или все скрытые файлы.
В результате должен появиться список каталогов, в которых есть только файл .DS_Store
:
checkDir() {
setopt extendedglob localoptions
REPLY=${${REPLY:h}:-.}
local -a files=($REPLY/^.DS_Store(NDY1))
return ${#files}
}
print -lr -- **/.DS_Store(.+checkDir)
Он использует квалификатор +
glob для фильтрации совпадающих результатов. Некоторые из частей:
**/.DS_Store(.+checkDir)
— начальный оператор glob:
**/
— поиск по текущему каталогу и его подкаталогам..DS_Store
— файлы с именем .DS_STORE
.(.)
— включать только обычные файлы.(+checkDir)
- проверьте каждый результат с помощью функции checkDir
.checkDir() ...
- zsh
функция:
setopt extendedglob localoptions
— включить расширенные операторы glob. При использовании localoptions
настройка будет применяться только к этой функции.REPLY=${${REPLY:h}:-.}
– REPLY
является одновременно входными и выходными данными функции.
${REPLY:h}
— входные данные — путь к файлу .DS_Store
; это даст нам базовый каталог (h
head).${...:-.}
- если каталог пуст, файл находится в текущем каталоге - установите отображаемый результат на .
.local -a files=($REPLY/^.DS_Store(NDY1))
— построить список файлов в каталоге в REPLY
.
$REPLY/^.DS_Store
— с ^
в списке будут файлы без имени .DS_Store
.(N)
- нет ошибки, если список пуст (N
ull).(D)
— включать имена файлов, начинающиеся с .
.(Y1)
- короткое замыкание. Только проверка на наличие файлов; это остановит построение списка, если что-нибудь будет найдено.return ${#files}
— установите код возврата для функции.
$#files == 0
— включите в результаты имя каталога, хранящееся в REPLY
.$#files != 0
— исключить эту запись из результатов.Пустые каталоги можно добавить, объединив приведенное выше выражение glob с другим выражением, использующим квалификатор (/^F)
:
=> print -lr -- **/ **/*(.D) | sort
aa/
bb/
bb/.DS_Store
cc/
cc/.DS_Store
cc/anotherfile
=> print -lr -- **/.DS_Store(N.+checkDir) **/*(N/^F)
bb
aa
=> cd bb
=> print -lr -- **/.DS_Store(N.+checkDir)
.
Отредактировано для добавления — это может быть немного короче, если в спецификации указаны пустые каталоги и каталоги, в которых все файлы начинаются с .
:
print -lr -- **/(e{'fl=($REPLY/*(NY1));((!$#fl))'})
Обозначение $REPLY/^.DS_Store
вполне достоверно!
Не просто, но мы могли бы сделать:
setopt extendedglob # for '~' and '#q' in the `[[ … ]]' form
setopt globstarshort # shortcut for '**/*' to '**'
print -rC1 -- **(DN/^F,/e['[[ -z $REPLY/*~*/.DS_Store(#qoNDNY1) ]]'])
перечисляет пустые каталоги или каталоги, в которых не существует ни одного файла кроме .DS_Store (другими словами: выходит только .DS_Store).
**(…)
:
GLOB_STAR_SHORT
ярлык для **/*
.
*(…)
: Глоб
отборочные
указать, какие имена файлов, которые в противном случае соответствуют данному шаблону, будут
быть вставлен в список аргументов.
D
: набор
GLOB_DOTS,
включить точечные файлы, каталоги.
N
: набор
NULL_GLOB,
не сигнализировать об ошибке, если шаблон не соответствует. (Не требуется для
особенно тестирование/экспериментирование.)
/^F
: идиома zsh для пустых каталогов.
,
: ИЛИ
/e[…]
: каталоги И e
строковый квалификатор, обозначающий каталоги
которые соответствуют строке кода zsh, то есть …
.
[[ -z … ]]
: будет описано, что другого файла, кроме .DS_Store
, не существует.
используя глобальные шаблоны.
$REPLY
: во время выполнения e[…]
имя файла в данный момент
проверено, в этом случае имя каталога будет передано через zsh.
*~*/.DS_Store
: X~Y
означает совпадение всего, что соответствует шаблону.
X
но не совпадает Y
. Таким образом, он будет расширять что-либо, кроме
.DS_Store
.
#q
: подстановка выполняется в форме [[ -z … ]]
.
oN
: нет.
D
:
GLOB_DOTS
снова.
N
: набор
NULL_GLOB,
пусть zsh не сигнализирует об ошибке во время обработки e[…]
.
Y1
: короткое замыкание, будет учитываться только первое совпадение.
достаточно.
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
Примечание: некоторые ссылки:
Glob Qualifires:
...
Можно объединить несколько таких списков, разделив их запятыми. весь список соответствует, если совпадает хотя бы один из подсписков (они `or'ed, квалификаторы в подсписках имеют `and'ed). Некоторый квалификаторы,--- Glob Qualifires, zshexpn(1)
Условные выражения:
...
Генерация имени файла не выполняется ни для какой формы аргумента. условия. Однако его можно принудительно выполнить в любом случае, когда обычная оболочка расширение допустимо, и когда действует опция EXTENDED_GLOB, используя явный квалификатор glob формы (#q) в конце нить.--- Условные выражения, zshmisc(1)
Ааа, я пытался заставить [[ -z <glob> ]]
работать, похоже, мне нужны были и extendedglob
, и формат квалификатора (#q...)
. Кое-что узнал - спасибо!
Поскольку это взаимоисключающие запросы, попробуйте
find /directory -empty -type d
, тогдаfind /directory -name ".DS_Store"