我正在尝试在匹配特定元数据的目录中索引pdf文件但由于某种原因,我正在寻找的字符串是否存在于我的元数据变量中,我的脚本将打印每个文件名。在这种情况下,我正在获取pdftk的输出并搜索字符串“InfoKey:Author”,我知道我的一些pdf不包含。但是我的脚本会吐出每个文件都包含它。
index() {
for file in *
do
[ -d "$file" ] && (cd "$file"; index)
if [ "$( echo "$file" | grep -E '.*\.pdf' )" ]; then
metadata="$(pdftk "$file" dump_data)"
[ -z $(grep -e '^InfoKey: Author' "$metadata" >/dev/null 2>&1) ]
if [ $? -eq 0 ]; then
echo "$file"
fi
fi
done
}
index
答案 0 :(得分:3)
bash
metadata="$(pdftk "$file" dump_data)"
[ -z $(grep -e '^InfoKey: Author' "$metadata" >/dev/null 2>&1) ]
if [ $? -eq 0 ]; then
echo "$file"
fi
grep
搜索文件。要使其解析pdftk
的输出,您无法在命令行上传递字符串,因为它会将其视为文件名。相反,使用管道:
pdftk "$file" dump_data | grep -e '^InfoKey: Author' >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "$file"
fi
写这个的惯用方法是将您正在测试的命令放入if
语句中。
if pdftk "$file" dump_data | grep -e '^InfoKey: Author' >/dev/null 2>&1; then
echo "$file"
fi
然后,您可以使用-q
来隐藏grep
:
if pdftk "$file" dump_data | grep -qe '^InfoKey: Author'; then
echo "$file"
fi
那很不错,不是吗?
find
是的,也许吧。但是,我们可以做得更好。我们来看看你的递归函数。在bash中进行递归搜索的最自然方式是使用find
。
首先,让我们从一个基本find
命令开始,该命令查找并打印当前目录或其子目录中的所有.pdf
文件。
find . -name '*.pdf' -print
这是一个好的开始。如果您没有做任何其他事情,可以使用它来替换代码中的显式递归。 (事实上,我给出的下一个命令是相当讨厌的,所以你可能想这样做。)如果你这样做,你可以做类似的事情:
find . -name '*.pdf' | while read file; do
# process each $file
done
但无论如何,在令人讨厌但又棒极了的find
命令中,它一举完成所有事情!
find . -name '*.pdf' \
-exec sh -c 'pdftk "$1" dump_data | grep -qe "^InfoKey: Author"' -- {} \; \
-print
这将以递归方式查找所有.pdf
个文件。然后它像以前一样运行pdftk
管道。
sh
shell的原因是能够使用-exec
执行管道。 -exec
只接受一个命令。要通过两个命令传递一个管道,我们需要添加一个间接层。这是sh
的内容。 -c
给出了运行命令,{}
是该命令的第一个参数。 {}
,您知道,是find
插入当前文件名的占位符。因此,当前文件名作为-c
命令行的第一个参数传递。在该命令中,文件名显示为$1
。
最后,如果整个命令行成功 - 如果grep -q
成功找到匹配项,则find
执行-print
操作,该操作将打印当前文件名。
答案 1 :(得分:2)
您没有测试bash
的状态,您正在测试[
(又名test
)的状态,该状态正在测试输出是否为空(它始终为空是因为你重定向输出)。此外,您使用$metadata
作为grep
的文件名参数;如果要测试其内容,则需要将其传递给命令:
if [ "$( echo "$file" | grep -E '.*\.pdf' )" ]; then
metadata="$(pdftk "$file" dump_data)"
echo "$metadata" | grep -e '^InfoKey: Author' >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "$file"
fi
fi