Как может только каталоги быть перечисленным, которые не имеют другого дочернего каталога?
Вообразите структуру как /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
справка (я не мог заставить это реагировать способ, которым я хотел это к)?
Вот совместимое 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:) }
Это - то, что я использую:
leaf () { find "${1:-.}" -depth -type d | sed 'h; :b; $b; N; /^\(.*\)\/.*\n\1$/ { g; bb }; $ {x; b}; P; D'; }
Назовите его с помощью каталога для запуска с:
leaf /start/dir