вывести список всех каталогов, содержащих файлы *.html, а также список файлов в каталогах

вывести список всех каталогов, содержащих файлы *.html, а также список файлов в каталогах

Я хотел бы получить список всех каталогов, содержащих HTML-документы, завершенные .htmили .htmlигнорирующие заглавные или строчные буквы.

Я пытался:

find / -type d -ls | tr -s [:blank:] | cut -d ' ' -f 11 | grep -i -e "*.htm" -e "*.html"

Но он выводит только список каталогов, а мне нужно вывести список содержимого этих каталогов, но я не знаю как.

Затем я попробовал:

find / -type d -exec ls -l {} \; | tr -s [:blank:] | cut -d ' ' -f 9 | grep -i -e ".htm" -e ".html"

И он их находит, но как мне распечатать каталоги, где они находятся?

решение1

Вот некоторые возможные команды, включая пример вывода.

Самый простой:

$ find / -iname "*.htm*"
foo/a.HTM
foo/b.HTML
foo/b.html
foo/x.htmx
foo/a.htm
bar/a.htm

-inameозначает находить файлы, соответствующие glob и быть нечувствительными к регистру. Проблема в том, что glob *.htm*также находит htmx.

Чтобы предотвратить обнаружение, htmxвам придется разделить шар:

$ find / -iname "*.htm" -o -iname "*.html"
foo/a.HTM
foo/b.HTML
foo/b.html
foo/a.htm
bar/a.htm

Или используйте grep, который может использовать регулярные выражения:

$ find / | grep -i "\.html*$"
foo/a.HTM
foo/b.HTML
foo/b.html
foo/a.htm
bar/a.htm

Обратите внимание, что regex отличается от glob. Особенно точка ( .) и звездочка ( *) имеют совершенно разные значения в glob и regex.

Видетьhttps://en.wikipedia.org/wiki/Glob_(программирование)#Сравнение_с_регулярными_выражениямиЧтобы получить больше информации.

решение2

С использованием zsh:

setopt extendedglob nullglob
for pathname in /**/*(/e{'[[ -n $REPLY/(#i)*.htm(l#)(#q.) ]]'}); do
    printf '%s:\n' $pathname
    ls -l $pathname
done

Это выводит путь к каждому каталогу, содержащему любой обычный файл, имя которого заканчивается на «» .htmили «» .html(независимо от регистра), а затем ls -lвывод для этого каталога.

Цикл проходит по каждому каталогу, /содержащему файл HTML, в котором он находится. Он делает это с помощью /**/*glob, который сам по себе соответствует всему во всей /иерархии каталогов. Этот список фильтруется, чтобы содержать только имена путей каталогов с помощью /квалификатора glob (инициал /в первых скобках), и список дополнительно фильтруется, чтобы содержать только те записи, для которых [[ -n $REPLY/(#i)*.htm(l#)(#q.) ]]является истинным. Это выражение, где $REPLY— одно из проверяемых имен путей каталогов, будет истинным, если каталог содержит хотя бы один обычный файл с суффиксом .htmили .htmlимени файла (без учета регистра).

Часть e{...}шаблона подстановки, вероятно, можно было бы записать более кратко.


С использованием bash:

shopt -s globstar nullglob extglob nocaseglob
for pathname in /**/*/; do
    set -- "$pathname"/*.htm?(l)
    if [[ -f $1 ]]; then
        printf '%s:\n' "${pathname%/}"
        ls -l "$pathname"
    fi
done

Это использует globstarопцию оболочки для включения использования **шаблона подстановки (включенного по умолчанию в zshоболочке). Он перебирает все пути к каталогам во всей иерархии каталогов снизу /вверх и пытается расширить глоб в каждом каталоге (это соответствует HTML-файлам, которые нас интересуют). Если первое совпадение этого глобуса является обычным файлом или символической ссылкой на него, то выводится *.htm?(l)путь к каталогу и список .ls -l

Если у вас естькаталогис суффиксом .htmимени .htmlфайла вам придется проверять совпадения расширения внутри цикла в отдельном цикле, просто чтобы убедиться, что вы перехватываете любые обычные файлы (или символические ссылки на обычные файлы) с суффиксами HTML:

shopt -s globstar extglob nocaseglob
for pathname in /**/*/; do
    for match in "$pathname"/*.htm?(l); do
        if [[ -f $match ]]; then
            printf '%s:\n' "${pathname%/}"
            ls -l "$pathname"
            break
        fi
    done
done

Я удалил nullglobопцию shell в этом варианте, так как она нам больше не нужна.


В оболочке POSIX shу вас нет доступа к **glob, поэтому вам придется использовать findдля генерации путей к каталогам для цикла:

find / -type d -exec sh -c '
    for pathname do
        for match in "$pathname"/*.[hH][tT][mM] "$pathname"/*.[hH][tT][mM][lL] ; do
            if [ -f "$match" ]; then
                printf "%s:\n" "${pathname%/}"
                ls -l "$pathname"
                break
            fi
        done
    done' sh {} +

Здесь findдействует как своего рода генератор путей для встроенного sh -cскрипта и передает ему пути к каталогам.

Скрипт sh -cделает примерно то же, что и 2-й bashвариант ответа, то есть он перебирает расширение glob, которое должно соответствовать искомым именам, проверяя каждое имя, чтобы увидеть, является ли оно обычным файлом (или символической ссылкой на него). Как только он находит файл, он печатает путь к каталогу, а затем вывод ls -l.

решение3

Я бы предложил использовать

find / '(' -iname '*.htm' -o -iname '*.html' ')' -printf '%h\n' | uniq | xargs -r -d '\n' ls -l

Первая часть, find / '(' -iname '*.htm' -o -iname '*.html' ')' -printf '%h\n', находит все файлы, которые заканчиваются на .htmили .htmlв верхнем или нижнем регистре (используя шаблоны glob), и выводит каталог ( %h) для каждого такого найденного файла, по одному каталогу на строку.

Из-за особенностей findсканирования каталогов в списке имеется один или несколько последовательных идентичных каталогов; uniqсохраняется только один из каждого каталога.

Наконец, мы передаем список каталогов в xargs, сообщая ему, что не следует запускать команду без каких-либо каталогов -r, и что разделителем является новая строка -d '\n'. Команда ls -l; измените по своему вкусу.

Если вам нужен только список каталогов, а не их содержимое, опустите эту xargsчасть:

find / '(' -iname '*.htm' -o -iname '*.html' ')' -printf '%h\n' | uniq

Связанный контент