Используя “находку” для списка только каталогов без большего количества childs

Как может только каталоги быть перечисленным, которые не имеют другого дочернего каталога?

Вообразите структуру как /A /A/AA /A/AB /A/AB/ABB /B /C /C/CC /C/CC/CCC /C/CC/CCC/CCCC Я хотел бы использовать find перечислять только /A/AA /A/AB/ABB /B /C/CC/CCC/CCCC.

Начальная точка была бы find . -type d, но ни один -mindepth ни -maxdepth может использоваться, может -noleaf справка (я не мог заставить это реагировать способ, которым я хотел это к)?

5
задан 14.10.2014, 14:43

2 ответа

Вот совместимое POSIX решение, которое постобрабатывает вывод find удалить каталоги, которые имеют перечисленный подкаталог. Это предполагает, что нет никаких новых строк в именах каталогов.

{ find . -type d; echo; } |
awk 'index($0,prev"/")!=1 && NR!=1 {print prev}
     1 {sub(/\/$/,""); prev=$0}'

Объяснение: awk сценарий задерживает печать каждой строки, пока это не считало следующую строку и только печатает предыдущую строку, если это не префикс. Это использует в своих интересах факт это find подкаталоги списков сразу после их родителя. Дополнительное "/" должен постараться не побочно удалять foo когда foobar также существует. Неэлегантное NR!=1 старается не печатать начальную пустую строку и неэлегантное echo; не должен иметь одинаково неэлегантного особого случая для последней строки. Вызов к sub удаляет запаздывающую наклонную черту с каталога верхнего уровня, в случае, если, например. find ./ был назван.


Как обычно, существует загадочная zsh острота.

echo **/.(e\''test -z $REPLY/*(/DN[1])'\':h)

Дольше, больше читаемой версии:

is_leaf () { [ -z $REPLY/*(/DN[1]) ] }
echo **/.(+is_leaf:h)

Последняя строка может быть упрощена до echo **/(+is_leaf) если Вы' не возражаете против запаздывания /.

Сводное объяснение: материал в круглых скобках является спецификаторами шарика, зарегистрированными в zshexpn страница справочника. Мы фильтруем результаты шарика **/ (расширяющийся до текущего каталога и всех его подкаталогов), сохраняя только тех, для который функция is_leaf (или код между '…') возвраты 0. Шарики кода фильтра подкаталоги протестированного соответствия ($REPLY) (на самом деле, [1] делает это останавливается после первого подкаталога), и возвращает состояние, указывающее, был ли по крайней мере один подкаталог найден. Спецификатор шарика / ограничивает расширение на каталоги; N означает, что расширение пусто, если там не идет ни в какое сравнение; D причины отмечают точкой файлы, которые будут включены; :h модификатор истории и вызывает /. суффикс, который будет разделен (в целом это означает dirname).

Только для иллюстрирования возможностей спецификаторов шарика zsh вот два других варианта (дольше, и я думаю более неясный) с соответствием is_leaf функция:

echo **/.(e\''tmp=($REPLY/*(/DN[1])); ((!#tmp))'\':h)
echo **/.(e\''$REPLY/*(/DN[1]e:REPLY=false:)'\':h)
is_leaf () { set -- $REPLY/*(/DN[1]); ((!#)); }
is_leaf () { return $REPLY/*(/DN[1]e:REPLY=1:) }
5
ответ дан 07.12.2019, 17:39

Это - то, что я использую:

leaf () { find "${1:-.}" -depth -type d | sed  'h; :b; $b; N; /^\(.*\)\/.*\n\1$/ { g; bb }; $ {x; b}; P; D'; }

Назовите его с помощью каталога для запуска с:

leaf /start/dir
1
ответ дан 07.12.2019, 17:39

Теги

Похожие вопросы