Gostaria de obter a lista de todos os diretórios que contém documentos HTML, finalizados .htm
ou .html
ignorando 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
-iname
significa 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, htmx
você 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
( .html
independentemente do caso), seguido pela ls -l
saí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 .htm
ou .html
nome 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 globstar
opção shell para habilitar o uso do **
padrão globbing (habilitado por padrão no zsh
shell). 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 -l
listagem serão exibidos.
Se você pode terdiretórioscom o sufixo .htm
on .html
filename, 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 nullglob
opção shell nesta variação, pois não dependemos mais dela.
No sh
shell POSIX você não tem acesso ao **
glob, então você teria que usar find
para 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, find
atua como uma espécie de gerador de nome de caminho para o sh -c
script incorporado e o alimenta com nomes de caminho de diretórios.
O sh -c
script faz praticamente o que a segunda bash
variaçã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 -l
saí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 .htm
ou .html
em 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 find
verifica os diretórios, há um ou mais diretórios idênticos consecutivos listados; uniq
reté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 -r
e 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 xargs
parte:
find / '(' -iname '*.htm' -o -iname '*.html' ')' -printf '%h\n' | uniq