bash - 无论输入如何,grep评估为true

时间:2014-02-13 22:39:06

标签: bash

我正在尝试在匹配特定元数据的目录中索引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

2 个答案:

答案 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