查找具有给定扩展名的所有文件,其基本名称是父目录的名称

Bri*_*ick 9 find

我想递归查找*.pdf目录中~/foo基本名称与文件父目录名称匹配的每个文件。

例如,假设目录结构~/foo如下所示

foo
??? dir1
?   ??? dir1.pdf
?   ??? dir1.txt
??? dir2
?   ??? dir2.tex
?   ??? spam
?       ??? spam.pdf
??? dir3
    ??? dir3.pdf
    ??? eggs
        ??? eggs.pdf
Run Code Online (Sandbox Code Playgroud)

运行我想要的命令会返回

~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf
Run Code Online (Sandbox Code Playgroud)

这是否可以使用find或其他一些核心实用程序?我认为使用-regex选项是可行的,find但我不确定如何编写正确的模式。

ded*_*sdi 16

使用 GNU find

find . -regextype egrep -regex '.*/([^/]+)/\1\.pdf'
Run Code Online (Sandbox Code Playgroud)
  • -regextype egrep 使用 egrep 风格的正则表达式。
  • .*/ 匹配祖父指令。
  • ([^/]+)/ 匹配组中的父目录。
  • \1\.pdf用于backreference将文件名匹配为父目录。

更新

一个人(我自己)可能认为这.*已经足够贪婪了,没有必要/从父匹配中排除:

find . -regextype egrep -regex '.*/(.+)/\1\.pdf'
Run Code Online (Sandbox Code Playgroud)

上面的命令不能很好地工作,因为它 mathches ./a/b/a/b.pdf

  • .*/ 火柴 ./
  • (.+)/ 火柴 a/b/
  • \1.pdf 火柴 a/b.pdf


Ini*_*ian 7

find .. -exec sh -c ''使用 shell 构造匹配基本名称和上面的直接路径的传统循环变体将在下面执行。

find foo/ -name '*.pdf' -exec sh -c '
    for file; do 
        base="${file##*/}"
        path="${file%/*}"
        if [ "${path##*/}" =  "${base%.*}" ]; then
            printf "%s\n" "$file" 
        fi
    done' sh {} +
Run Code Online (Sandbox Code Playgroud)

分解单个参数扩展

  • file包含.pdffind命令返回的文件的完整路径
  • "${file##*/}"只包含最后一个之后的部分,/即只包含文件的基本名称
  • "${file%/*}"包含到最终/ie的路径,结果的 basename 部分除外
  • "${path##*/}"包含在最后部分/path变量,即:该文件的基本名称上面立即文件夹路径
  • "${base%.*}"包含.pdf删除扩展名的基本名称部分

因此,如果没有扩展名的基本名称与上面直接文件夹的名称匹配,我们将打印路径。


Kus*_*nda 7

Inian 的答案相反,即查找目录,然后查看它们是否包含具有特定名称的文件。

以下打印找到的文件相对于目录的路径名foo

find foo -type d -exec sh -c '
    for dirpath do
        pathname="$dirpath/${dirpath##*/}.pdf"
        if [ -f "$pathname" ]; then
            printf "%s\n" "$pathname"
        fi
    done' sh {} +
Run Code Online (Sandbox Code Playgroud)

${dirpath##*/}将被目录路径的文件名部分替换,并且可以被替换为$(basename "$dirpath").

对于喜欢短路语法的人:

find foo -type d -exec sh -c '
    for dirpath do
        pathname="$dirpath/${dirpath##*/}.pdf"
        [ -f "$pathname" ] && printf "%s\n" "$pathname"
    done' sh {} +
Run Code Online (Sandbox Code Playgroud)

这样做的好处是您可能拥有比目录更多的 PDF 文件。如果通过较小的数量(目录数量)限制查询,则涉及的测试数量会减少。

例如,如果单个目录包含 100 个 PDF 文件,这将仅尝试检测其中一个,而不是根据目录的名称测试所有 100 个文件的名称。