我的脚本中的grep命令返回空结果,但从命令行工作

时间:2017-07-02 03:09:19

标签: bash shell

我正在尝试编写一个bash脚本,以便找到包含特定字符串的文件。该脚本调用另一个返回格式字符串的脚本:

url=title

title是我要找的字符串。 title可以包含如下所示的值:'A Soldier Of The Legion'。 我试图在/tmp/audiobooks目录中找到包含标题'A Soldier Of The Legion'的文件。 /tmp/audiobooks中的所有文件的名称都以AB.yaml结尾。

这是脚本:

#!/bin/sh

get_pairs='/home/me/util/scripts/get-pairs.sh'
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for i in `$get_pairs`
do
        echo "pair $i"
        url=`echo $i | cut -d= -f1`
        apptitle=`echo $i | cut -d= -f2- | cut -c1-52`
        echo "grep -l $apptitle /tmp/audiobooks/*AB.yaml | head -1"
        the_file=$(grep -l $apptitle /tmp/audiobooks/*AB.yaml | head -1)
        echo "the_file=$the_file"
        if [ -z $the_file ]
        then
                echo "No hiera file found for $apptitle ... skipping"
                continue
        fi
        appname=`basename $the_file .yaml`
        echo "url is[$url] and apptitle is [$apptitle] appname is [$appname]"
        exit 0
done
IFS=$SAVEIFS

脚本产生的输出是:

pair http://www.example.com/product/B06XK9FGYD='A Soldier Of The Legion'
grep -l 'A Soldier Of The Legion' /tmp/audiobooks/*AB.yaml | head -1
the_file=
No hiera file found for 'A Soldier Of The Legion' ... skipping
pair http://www.example.com/product/B01GWQI0OS='Art of War Sun Tzu'
grep -l 'Art of War Sun Tzu' /tmp/audiobooks/*AB.yaml | head -1
the_file=
No hiera file found for 'Art of War Sun Tzu' ... skipping
pair http://www.example.com/product/B0717333MM='Bartleby, the Scrivener (version 2)'
grep -l 'Bartleby, the Scrivener (version 2)' /tmp/audiobooks/*AB.yaml | head -1
the_file=/tmp/audiobooks/BartlebyTheScrivener_AMZAD_AB.yaml
url is[http://www.example.com/product/B0717333MM] and apptitle is ['Bartleby, the Scrivener (version 2)'] appname is [BartlebyTheScrivener_AMZAD_AB]

奇怪的是,当我从命令行运行它时,我回应的每个grep命令都有效...例如:

$ grep -l 'A Soldier Of The Legion' /tmp/audiobooks/*AB.yaml | head -1
/tmp/audiobooks/A_Soldier_of_the_Legion_AB.yaml

该脚本适用于标题'Bartleby, the Scrivener (version 2)'

3 个答案:

答案 0 :(得分:3)

如果这一行:

echo "grep -l $apptitle /tmp/audiobooks/*AB.yaml | head -1"

生成如下输出:

grep -l 'A Soldier Of The Legion' /tmp/audiobooks/*AB.yaml | head -1

然后,这意味着apptitle的值包含单引号。

您可以尝试这样做以了解发生了什么:

value1='A Soldier Of The Legion'
value2="'A Soldier Of The Legion'"
echo "$value1"
echo "$value2"

输出:

A Soldier Of The Legion
'A Soldier Of The Legion'

换句话说,脚本真正执行的是:

grep -l "'A Soldier Of The Legion'" /tmp/audiobooks/*AB.yaml | head -1

仅当yaml文件包含由单引号括起的标题时才会匹配。

您可能想要从apptitle中删除单引号,例如:

apptitle=$(echo $i | cut -d= -f2- | cut -c1-52 | sed -e "s/^'//" -e "s/'$//")

上面的sed将在每一端删除单引号,并在字符串的中间留下其他单引号。

答案 1 :(得分:1)

$apptitle包含标题周围的开始和结束单引号(')字符,您的脚本会将它们传递给grep

  • 阅读您的脚本很容易错过,因为您的脚本告诉用户它正在运行的命令 - 以及您手动运行 - 允许shell执行quote removal,因此不会通过这些字符为grep。这就是说您的脚本没有运行您希望它运行的grep命令。
  • 如果您的某些.yaml文件在搜索的标题周围有单引号,则该脚本将适用于这些文件。但它对其他人不起作用。 (我希望这就是它适用于你的一个游戏的原因。)

根据您的问题的早期编辑记录,您似乎可能已考虑过这种可能性,并试图通过更改来阻止它

the_file=$(grep -l "$apptitle" /tmp/audiobooks/*AB.yaml | head -1)

改为:

the_file=$(grep -l $apptitle /tmp/audiobooks/*AB.yaml | head -1)

这不会有帮助。 '仍在那里。 (我建议撤消这种改变,但由于你已经分配了IFS的价值,这可能没问题。)

当参数展开(')的结果中出现$apptitle等引用字符时,shell不会特别对待它。它不会阻止word splitting,也不会受quote removal的限制。

例如,当IFS具有默认值时,x="'a b c'"; printf '(%s)' $x的输出为('a)(b)(c'),而不是(a b c)。也就是说,当x保留值'a b c'时,不带引号的$x会扩展为'a b c',而分词会将其转换为'a {{1 }} b

在您的情况下,您已更改c',因此拆分仅发生在换行符和退格键上。 IFS匹配行,因此您无法在标题中获得换行符。假设标题不包含退格,那么保持grep不加引号是很好的(尽管可能风格上令人困惑)。但是这并没有删除封闭的$apptitle个字符。

答案 2 :(得分:0)

我认为在执行.时需要放置get-pairs.sh(点)。前面的点意味着将该文件的内容“源”到当前shell中。

for i in `. $get_pairs`
相关问题