Zsh glob для поиска пустых каталогов или содержащих только .DS_Store

Есть ли какой-нибудь zsh glob, который найдет пустые каталоги или содержащие только файл .DS_Store?

Я знаю, что комбинация флагов (/^F) glob найдет пустые каталоги, но я также хочу включить каталоги, которые содержат только файл .DS_Store, но не содержат других узлов (файлов, каталогов и т. д.).

Для моих целей, если я не могу отфильтровать конкретно .DS_Store, достаточно отфильтровать все скрытые файлы (.*).


2
82
2

Ответы:

В результате должен появиться список каталогов, в которых есть только файл .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; это даст нам базовый каталог (hhead).
      • ${...:-.} - если каталог пуст, файл находится в текущем каталоге - установите отображаемый результат на ..
    • local -a files=($REPLY/^.DS_Store(NDY1)) — построить список файлов в каталоге в REPLY.
      • $REPLY/^.DS_Store — с ^ в списке будут файлы без имени .DS_Store.
      • (N) - нет ошибки, если список пуст (Null).
      • (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))'})

Решено

Не просто, но мы могли бы сделать:

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)


Интересные вопросы для изучения

Zsh: совпадений не найдено: MulticateLists(np.array([1,3,5,6,4,6,7,1,2,7]))Как использовать пользовательскую функцию предварительного просмотра для команды fzf в zshGawk зависает при использовании регулярного выражения для RS в сочетании с чтением непрерывного потока со стандартного вводаZsh-скрипт, использующий отформатированную строку даты в команде FFMPEGZsh — Как присвоить переменной строку miltiline json с подставленными значениямиКак эффективно выполнять параллельный поиск файлов с использованием pathlib `glob` в Python для больших структур каталогов?Как я могу объединить несколько файлов CSV в один лист Excel с помощью Python?Powershell & bash: получить все файлы, соответствующие каталогу по пути и имени файлаМой код работает только с одним файлом изображения, остальные файлы изображений считываются и сохраняются, но мой код не затрагивает их. Мне нужно, чтобы мой код работал со всеми файлами изображенийОпределите входные файлы для Snakemake, используя glob