我想取得包含 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
這使用globstar
shell 選項來啟用**
通配模式(預設在zsh
shell 中啟用)。它從下到上迭代整個目錄層次結構中的所有目錄路徑名/
,並嘗試擴展*.htm?(l)
每個目錄中的 glob(這與我們感興趣的 HTML 檔案相符)。如果該 glob 的第一個匹配項是常規文件或指向該文件的符號鏈接,則ls -l
輸出目錄路徑名和列表。
如果你可能有目錄使用.htm
on.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
shell 中,您無法存取 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