列出所有包含 *.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

請注意,正規表示式與 glob 不同。特別是點 ( .) 和星號 ( *) 在 glob 和正規表示式中具有非常不同的意義。

https://en.wikipedia.org/wiki/Glob_(programming)#Compared_to_regular_expressions了解更多。

答案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 本身就會匹配整個/目錄層次結構中的所有內容。此清單透過/glob 限定詞(第一個括號中的首字母)過濾為僅包含目錄路徑名/,並且該清單進一步過濾為僅包含那些為[[ -n $REPLY/(#i)*.htm(l#)(#q.) ]]true 的條目。$REPLY如果目錄至少包含一個帶有 a.htm.html文件名後綴(不區分大小寫)的常規文件,則此表達式(其中 是正在檢查的目錄路徑名之一)將為 true。

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

這使用globstarshell 選項來啟用**通配模式(預設在zshshell 中啟用)。它從下到上迭代整個目錄層次結構中的所有目錄路徑名/,並嘗試擴展*.htm?(l)每個目錄中的 glob(這與我們感興趣的 HTML 檔案相符)。如果該 glob 的第一個匹配項是常規文件或指向該文件的符號鏈接,則ls -l輸出目錄路徑名和列表。

如果你可能有目錄使用.htmon.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 shshell 中,您無法存取 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腳本的作用與答案的第二個變體的作用幾乎相同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

相關內容