我试图在一个匹配特定元数据的目录中索引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
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
。
最后,如果整个命令行成功—如果CCD_ 24成功地找到匹配—则find
执行打印当前文件名的-print
动作。
您没有测试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