我想递归查找*.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.pdffind .. -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包含.pdf从find命令返回的文件的完整路径"${file##*/}"只包含最后一个之后的部分,/即只包含文件的基本名称"${file%/*}"包含到最终/ie的路径,结果的 basename 部分除外"${path##*/}"包含在最后部分/从path变量,即:该文件的基本名称上面立即文件夹路径"${base%.*}"包含.pdf删除扩展名的基本名称部分因此,如果没有扩展名的基本名称与上面直接文件夹的名称匹配,我们将打印路径。
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 个文件的名称。