liste todos os diretórios contendo arquivos *.html e também liste os arquivos nos diretórios

liste todos os diretórios contendo arquivos *.html e também liste os arquivos nos diretórios

Gostaria de obter a lista de todos os diretórios que contém documentos HTML, finalizados .htmou .htmlignorando maiúsculas ou minúsculas.

Eu tentei:

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

Mas ele lista apenas diretórios, e preciso listar o conteúdo desses diretórios e não sei como.

Eu então tentei:

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

E os encontra, mas como imprimo os diretórios onde eles estão?

Responder1

Aqui estão alguns comandos possíveis, incluindo exemplos de saída

O mais simples:

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

-inamesignifica encontrar arquivos que correspondam ao glob e não diferenciar maiúsculas de minúsculas. O problema é que o globo *.htm*também encontra arquivos htmx.

Para evitar a descoberta, htmxvocê deve dividir o globo:

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

Ou use grep que pode usar regex:

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

Observe que regex é diferente de glob. Especialmente o ponto ( .) e a estrela ( *) têm significados muito diferentes em glob e regex.

Verhttps://en.wikipedia.org/wiki/Glob_(programming)#Compared_to_regular_expressionsPara maiores informações.

Responder2

Usando zsh:

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

Isso imprime o nome do caminho de cada diretório que contém qualquer arquivo regular cujo nome termine com ou .htm( .htmlindependentemente do caso), seguido pela ls -lsaída desse diretório.

O loop percorre cada diretório dentro ou abaixo /que contém um arquivo HTML. Ele faz isso usando o /**/*glob que, por si só, corresponde a tudo em toda a /hierarquia de diretórios. Esta lista é filtrada para conter apenas nomes de caminhos de diretório pelo /qualificador glob (a inicial /no primeiro parêntese), e a lista é ainda filtrada para conter apenas as entradas para as quais [[ -n $REPLY/(#i)*.htm(l#)(#q.) ]]é verdadeira. Esta expressão, onde $REPLYé um dos nomes de caminho de diretório que está sendo examinado, será verdadeira se um diretório contiver pelo menos um arquivo regular com um sufixo .htmou .htmlnome de arquivo (sem distinção entre maiúsculas e minúsculas).

A e{...}parte do padrão global provavelmente poderia ser escrita de forma mais sucinta.


Usando 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

Isso usa a globstaropção shell para habilitar o uso do **padrão globbing (habilitado por padrão no zshshell). Ele itera sobre todos os nomes de caminho de diretório em toda a hierarquia de diretórios, de /baixo para cima, e tenta expandir o *.htm?(l)glob em cada diretório (isso corresponde aos arquivos HTML nos quais estamos interessados). Se a primeira correspondência deste glob for um arquivo normal ou um link simbólico para um, então o nome do caminho do diretório e a ls -llistagem serão exibidos.

Se você pode terdiretórioscom o sufixo .htmon .htmlfilename, você teria que testar as correspondências da expansão dentro do loop em um loop separado, apenas para ter certeza de capturar quaisquer arquivos regulares (ou links simbólicos para arquivos regulares) com os sufixos 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

Excluí a nullglobopção shell nesta variação, pois não dependemos mais dela.


No shshell POSIX você não tem acesso ao **glob, então você teria que usar findpara gerar os nomes dos caminhos dos diretórios para o loop:

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 {} +

Aqui, findatua como uma espécie de gerador de nome de caminho para o sh -cscript incorporado e o alimenta com nomes de caminho de diretórios.

O sh -cscript faz praticamente o que a segunda bashvariação da resposta faz, ou seja, itera sobre a expansão do glob que deve corresponder aos nomes desejados, testando cada nome para ver se é um arquivo normal (ou um link simbólico para um). Depois de encontrar um arquivo, ele imprime o nome do caminho do diretório seguido pela ls -lsaída.

Responder3

Eu sugeriria usar

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

A primeira parte, find / '(' -iname '*.htm' -o -iname '*.html' ')' -printf '%h\n', encontra todos os arquivos que terminam com .htmou .htmlem letras maiúsculas ou minúsculas (usando padrões glob) e imprime o diretório ( %h) para cada arquivo encontrado, um diretório por linha.

Devido à forma como findverifica os diretórios, há um ou mais diretórios idênticos consecutivos listados; uniqretém apenas um de cada.

Por fim, alimentamos a lista de diretórios xargs, informando-o para não executar um comando sem nenhum diretório -re que o separador é uma nova linha -d '\n'. O comando é ls -l; modifique ao seu gosto.

Se você precisar apenas da lista de diretórios, e não do conteúdo dos diretórios, elimine a xargsparte:

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

informação relacionada