使用基于命令输出的条件

时间:2010-07-20 23:02:16

标签: bash

我有以下代码:

#!/bin/bash

for f in `find . ! -type d`;
do
        line=`grep -i 'todo' $f | sed 's/^[ \t]*//'`
        if [ $line ]; then
                echo "$f:"
                echo "$line"
        fi
done

但是条件不能像我期望的那样工作,我需要它才能在命令返回空字符串(或什么都没有)之外的情况下工作。

7 个答案:

答案 0 :(得分:4)

正如Alberto所指出的,通常使用-n检查字符串是否具有非零长度,但在字符串可能为空或仅包含空格的情况下,您需要引用变量:

if [ -n "$line" ] # ...

同样,您可以使用-z检查其长度是否为零:

if [ -z "$line" ] # ...

当更有意义时,也支持否定:

if [ ! -z "$line" ] # ...

编辑:由于你正在使用bash,你实际上可以使用其他一些不错的功能,例如:

  1. 双括号(例如[[ expr ]])和
  2. 正则表达式(例如[[ cat =~ ca[bat] ]]
  3. 有关详细信息,请参阅man bash中的conditional constructs部分。

答案 1 :(得分:3)

一些想法:

  • 您需要引用$f行中的grep来处理名称中包含空格的文件。
  • 也许你应该使用-f而不是! -d,否则你的发现可能会挂起来。
  • 对我来说,\t转义不能作为选项卡匹配,它在测试用例文件行中消耗了一个前导t,所以我只是在脚本中插入一个原始制表符而不是。
  • 使用double square bracket test,否则你需要一个操作员,或者至少需要一些报价。

您的脚本会略有不同:

find . -type f | while read f
do
        # raw tab in here ------------------- v
        line=`grep -i 'todo' "$f" | sed 's/^[  ]*//'`
        if [[ $line ]]; then
                echo "$f:"
                echo "$line"
        fi
done

答案 2 :(得分:2)

旧的学校符号(可用于Bourne Shell等古老的东西,而不是Korn shell等古老的东西)是:

for f in `find . ! -type d`
do
    line=`grep -i 'todo' $f | sed 's/^[ \t]*//'`
    if [ -n "$line" ]
    then
            echo "$f:"
            echo "$line"
    fi
done

但是,您可以使用以下方法加快整体处理速度:

find . ! -type d -print0 | xargs -0 grep -i 'todo' /dev/null |
perl -p -e '($name) = split /:/;
            if ($saved ne $name) { $saved = $name; print "$name:\n"; }
            s/^$name:\s*//;'

修改find以处理名称中的空格; xargs还处理名称中的空格,并在/ dev / null和一些文件上运行grep命令 - 这可确保匹配的行前面有文件名。 perl脚本在第一个冒号处拆分行 - 因此包含冒号的文件名不是好消息。它将该名称与之前保存的名称进行比较;如果它们不同,那么它会打印出新名称,冒号和换行符,以便为您提供文件标题。然后在(自动)打印行之前删除文件名和尾随空格。 (不要在Perl中使用'-w';它会抱怨$ saved未初始化。如果必须(这是一个好习惯),请添加BEGIN { $saved = ""; }。)

这可能比shell循环执行得更好,因为它只调用grep几次而不是每个文件调用一次,并且根本不调用sed(而不是每个文件调用一次)。

答案 3 :(得分:1)

if [ -n $line ]

检查$line是否为空字符串。

答案 4 :(得分:0)

这是我喜欢的:

if [ ${PIPESTATUS[0]} -eq 0 ]; then echo lines found; fi

它采用grep的退出状态。手册页告诉:

EXIT STATUS
   Normally,  the  exit  status  is  0  if  selected lines are found and 1 otherwise.

答案 5 :(得分:0)

如果可以,请使用POSIX字符类:

# cf. http://en.wikipedia.org/wiki/Regular_expression#POSIX_character_classes

sed 's/[[:blank:]]/-wasTabOrSpace-/g' <<< $'abc\t def'

答案 6 :(得分:0)

由于我们分别因为`...`或$(...)构造而有子shell,我们可以像使用指定的基于PIPESTATUS的退出代码的任何其他(父)shell一样退出子shell! : - )

# simple test
var="$(echooo hello 2>/dev/null | cat)"
echo ${PIPESTATUS[0]}  # 0

var="$(echooo hello 2>/dev/null | cat; exit ${PIPESTATUS[0]})"
echo ${PIPESTATUS[0]}  # 127