将grep命令的输出重定向到文件

8
我不确定为什么代码中提供的重定向无法正常工作。每次运行脚本时,输出文件总是为空。有人知道原因吗?
谢谢。
#!/bin/sh

LOOK_FOR="DefaultProblem"
FILES=`ls plugins/*source*.jar`

for i in $FILES
  do
    # echo "Looking in $i ..."
    unzip -p $i | grep -i $LOOK_FOR > output #> /dev/null 
    if [ $? == 0 ]
    then
      echo ">>>> Found $LOOK_FOR in $i <<<<"
    fi
  done

2
对于以后参考,“不工作”不是一个好的描述。告诉我们它为什么不工作。 - Keith Thompson
1
假设你会认真听取我的建议,这将对你未来可能遇到的任何问题都非常相关。我没有提到问题相关的事情,因为它已经被回答了。这就是评论的作用。我确实想在这里帮助你。请考虑我可能有一个有效观点的可能性。 - Keith Thompson
1
@fabricemarcelin:发表评论就是参与讨论。 - William Pursell
@KeithThompson 我已经更新了问题并解释了问题。 - fabricemarcelin
2
除了Keith Thompson的评论之外(也为了未来读者的利益),您可以使用bash -x ./scriptName.sh执行脚本(请参见http://www.cyberciti.biz/tips/debugging-shell-script.html),这将逐行展示脚本的执行过程。对于其他shell,请谷歌搜索“debug <shellname> <scriptname>”。这将帮助您更好地了解为什么脚本会失败。 - Aaron Newton
4个回答

10

你可能想要使用>>(追加)而不是>(覆盖)来进行重定向,如下所示:

unzip -p $i | grep -iF "$LOOK_FOR" >> output

由于您正在循环执行此命令并在每次执行中覆盖文件output,如果最后一个grep命令在解压输出中没有找到任何匹配行,则文件output可能会在最后为空。


1
太棒了,它像魔法一样运行。我完全没有想到那个。谢谢。 - fabricemarcelin

3
你有三个问题:
  1. 不要尝试解析 ls 的输出。相反,只需使用 for i in plugins/*source*.jar。主要原因是如果文件名中有空格,你的脚本将完全崩溃。请参阅此链接,了解不解析 ls 的多种原因。
  2. 你需要使用 >> 而不是 >,因为后者会在每次循环迭代时覆盖输出文件。而前者会追加到它上面。
  3. 使用更多引号!你需要引用你的变量,以确保它们不受单词拆分的影响。

此外,你可以内联 if 测试。把它们放在一起,我们有:

#!/bin/sh

LOOK_FOR="DefaultProblem"
for i in plugins/*source*.jar
do
    # echo "Looking in $i ..."
    if unzip -p "$i" | grep -i "$LOOK_FOR" >> output #> /dev/null
    then
      echo ">>>> Found $LOOK_FOR in $i <<<<"
    fi
done

谢谢你的建议,我会考虑的。 - fabricemarcelin
2
由于这是逐个搜索多个文件,因此所显示的 grep 输出不包含标识每行来自哪个文件的文件名。有时您可以通过在 grep 命令行中添加 /dev/null 来修复它;不幸的是,这不是其中之一。您需要在 >> 重定向之前添加:| sed "s%^%$i:%" - Jonathan Leffler
@JonathanLeffler 好主意,但在这种情况下,我建议只使用grep-l标志。 - SiegeX

2
您可以重定向整个循环的输出:
#!/bin/sh

LOOK_FOR="DefaultProblem"
FILES=`ls plugins/*source*.jar`

for i in $FILES ; do
    # echo "Looking in $i ..." 1>&2
    unzip -p $i | grep -i $LOOK_FOR
    if [ $? == 0 ] ; then
        echo ">>>> Found $LOOK_FOR in $i <<<<" 1>&2
    fi
done > output

请注意,我已将诊断消息重定向到标准错误流(stderr)。

0

你可以使用一个 find 命令代替一个 for 循环 和一个 if 条件语句 来完成所有操作

find /path/to/plugins -name "*source*.jar" -exec sh -c 'unzip -l "{}" | grep -q DefaultProblem' \; -print

即使使用 find 命令的输出,对于文件名中包含空格的文件也会出现错误。解决这个问题的办法是使用 find 命令的 -print0 标志以及在 Bash 中使用进程替换的 while IFS= -r -d '' line 循环。或者更好的方法是使用 Bash 4 的 globstar。 - SiegeX
@SiegeX已经修改了答案,提供了一些新的东西。 - jaypal singh
1
如果这样做可以运行,那肯定不是可移植的。相反,您需要将“{}”作为参数传递给shell。find /path/to/plugins -name "*source*.jar" -exec sh -c 'for f; do unzip -l "$f" | grep -q DefaultProblem; done' _ {} \; -print。下划线是一个丢弃的参数,它是必需的,因为shell的第一个参数是名称。 - SiegeX
感谢 @SiegeX。我会留给OP使用这个数据尝试一下。但是感谢您的反馈。那是很有价值的东西。我以为学习Bash、awk和sed三个月就足够了,但现在已经过去了四个月并且还在继续学习 :) - jaypal singh
两点都是真的。我非常喜欢lynda.com的视频培训课程,因为我往往会在书本中迷失方向。上周末刚完成了Bill Weinman的Perl Essentials 5。现在头脑中充斥着所有的信息。 :) - jaypal singh
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接