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

相关内容