Listet alle Verzeichnisse auf, die *.html-Dateien enthalten, und listet auch die Dateien in den Verzeichnissen auf

Listet alle Verzeichnisse auf, die *.html-Dateien enthalten, und listet auch die Dateien in den Verzeichnissen auf

Ich möchte die Liste aller Verzeichnisse erhalten, die HTML-Dokumente enthalten, vollständig .htmoder .htmlohne Berücksichtigung der Groß- und Kleinschreibung.

Ich habe versucht:

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

Es werden jedoch nur Verzeichnisse aufgelistet, und ich muss den Inhalt dieser Verzeichnisse auflisten und weiß nicht wie.

Ich habe dann versucht:

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

Und es findet sie, aber wie drucke ich die Verzeichnisse aus, in denen sie sich befinden?

Antwort1

Hier sind einige mögliche Befehle einschließlich Beispielausgabe

Das Einfachste:

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

-inamebedeutet, Dateien zu finden, die mit glob übereinstimmen, und dabei nicht zwischen Groß- und Kleinschreibung zu unterscheiden. Das Problem ist, dass der glob *.htm*auch findet htmx.

Um das Finden zu verhindern, htmxmüssen Sie den Glob aufteilen:

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

Oder verwenden Sie grep, das reguläre Ausdrücke verwenden kann:

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

Beachten Sie, dass Regex nicht dasselbe ist wie Glob. Insbesondere der Punkt ( .) und der Stern ( *) haben in Glob und Regex sehr unterschiedliche Bedeutungen.

Sehenhttps://en.wikipedia.org/wiki/Glob_(programming)#Compared_to_regular_expressionsfür mehr Informationen.

Antwort2

Verwendung von zsh:

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

Dies druckt den Pfadnamen jedes Verzeichnisses, das eine reguläre Datei enthält, deren Name mit oder endet .htm( .htmlunabhängig von der Groß-/Kleinschreibung), gefolgt von der ls -lAusgabe für dieses Verzeichnis.

Die Schleife durchläuft alle Verzeichnisse, in denen oder darunter /eine HTML-Datei enthalten ist. Dies geschieht mithilfe des /**/*Globs, der für sich genommen alles in der gesamten /Verzeichnishierarchie abgleicht. Diese Liste wird so gefiltert, dass sie nur Verzeichnispfadnamen enthält, die durch den /Glob-Qualifizierer (den Anfangsbuchstaben /in der ersten Klammer) bestimmt werden, und die Liste wird weiter gefiltert, sodass sie nur die Einträge enthält, für die [[ -n $REPLY/(#i)*.htm(l#)(#q.) ]]wahr ist. Dieser Ausdruck, wobei $REPLYeiner der untersuchten Verzeichnispfadnamen ist, ist wahr, wenn ein Verzeichnis mindestens eine reguläre Datei mit einem Dateinamensuffix oder enthält (ohne Berücksichtigung der Groß-/Kleinschreibung) .htm..html

Der e{...}Teil des Globbing-Musters könnte wahrscheinlich prägnanter geschrieben werden.


Verwendung von 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

Dies verwendet die globstarShell-Option, um die Verwendung des **Globbing-Musters zu aktivieren (standardmäßig in der zshShell aktiviert). Es durchläuft alle Verzeichnispfadnamen in der gesamten Verzeichnishierarchie von /unten und versucht, den Glob in jedem Verzeichnis zu erweitern *.htm?(l)(dies entspricht den HTML-Dateien, an denen wir interessiert sind). Wenn die erste Übereinstimmung dieses Globs eine normale Datei oder ein symbolischer Link zu einer solchen ist, werden der Verzeichnispfadname und die ls -lAuflistung ausgegeben.

Wenn Sie möglicherweiseVerzeichnissemit dem Suffix .htm„on .htmlfilename“ müssten Sie die Übereinstimmungen der Erweiterung innerhalb der Schleife in einer separaten Schleife testen, nur um sicherzustellen, dass Sie alle regulären Dateien (oder symbolischen Links zu regulären Dateien) mit den HTML-Suffixen erfassen:

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

Ich habe die nullglobShell-Option in dieser Variante gelöscht, da wir nicht mehr davon abhängig sind.


Da Sie in der POSIX- shShell keinen Zugriff auf den Glob haben **, müssen Sie findzur Generierung der Verzeichnispfadnamen für die Schleife Folgendes verwenden:

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

Hierbei findfungiert es als eine Art Pfadnamengenerator für das eingebettete sh -cSkript und speist es mit Pfadnamen von Verzeichnissen.

Das sh -cSkript macht im Wesentlichen das Gleiche wie die zweite bashVariante der Antwort, d. h. es durchläuft die Erweiterung des Globs, die mit den gewünschten Namen übereinstimmen sollte, und prüft jeden Namen, um festzustellen, ob es sich um eine normale Datei handelt (oder um einen symbolischen Link zu einer solchen). Sobald es eine Datei findet, druckt es den Verzeichnispfadnamen, gefolgt von der ls -lAusgabe.

Antwort3

Ich würde vorschlagen,

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

Der erste Teil, , findet alle Dateien, die mit oder in Groß- oder Kleinbuchstaben find / '(' -iname '*.htm' -o -iname '*.html' ')' -printf '%h\n'enden (unter Verwendung von Glob-Mustern) und druckt das Verzeichnis ( ) für jede gefundene Datei, ein Verzeichnis pro Zeile..htm.html%h

Aufgrund der Art und Weise , wie findVerzeichnisse gescannt werden, werden ein oder mehrere aufeinanderfolgende identische Verzeichnisse aufgelistet; uniqvon jedem wird nur eines behalten.

Schließlich geben wir die Liste der Verzeichnisse an weiter xargsund sagen ihm, dass er keinen Befehl ohne Verzeichnisse ausführen soll -rund dass das Trennzeichen eine neue Zeile ist -d '\n'. Der Befehl lautet ls -l; ändern Sie ihn nach Ihren Wünschen.

Wenn Sie nur die Liste der Verzeichnisse und nicht deren Inhalt benötigen, lassen Sie den xargsTeil weg:

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

verwandte Informationen