我想获取包含 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