15

我敢肯定,perl、ruby、bash 有一些微不足道的单行代码,可以让我在循环中运行命令,直到我在 stdout 中观察到一些字符串,然后停止。理想情况下,我也想捕获标准输出,但如果它要控制台,那可能就足够了。

目前有问题的特定环境是 RedHat Linux,但有时在 Mac 上也需要同样的东西。因此,通用和 *nixy 将是最好的。不关心 Windows - 大概一个 *nixy 的东西可以在 cygwin 下工作。

更新:请注意,“观察一些字符串”是指“stdout 包含一些字符串”而不是“stdout 是一些字符串”。

4

8 回答 8

13

在 Perl 中:

#!/usr/local/bin/perl -w

if (@ARGV != 2)
{
    print "Usage: watchit.pl <cmd> <str>\n";
    exit(1);
}

$cmd = $ARGV[0];
$str = $ARGV[1];

while (1)
{
    my $output = `$cmd`;
    print $output; # or dump to file if desired
    if ($output =~ /$str/)
    {
        exit(0);
    }
}

例子:

[bash$] ./watchit.pl ls stop
watchit.pl
watchit.pl~
watchit.pl
watchit.pl~
... # from another terminal type "touch stop"
stop 
watchit.pl
watchit.pl~

不过,您可能想在其中添加一个睡眠。

于 2008-09-24T18:26:22.000 回答
11

有很多方法可以做到这一点,首先想到的是:

OUTPUT=""; 
while [ `echo $OUTPUT | grep -c somestring` = 0 ]; do 
  OUTPUT=`$cmd`; 
done

$cmd 是您要执行的命令。

最重要的是,这里有一个 BASH 函数版本,所以如果你想定期从交互式 shell 调用它,你可以更容易地调用它:

function run_until () {
  OUTPUT="";
  while [ `echo $OUTPUT | grep -c $2` = 0 ]; do
    OUTPUT=`$1`;
    echo $OUTPUT;
  done
}

免责声明:仅经过轻微测试,如果您的命令有很多参数或字符串包含特殊字符,可能需要进行一些额外的转义等。

编辑:根据亚当评论的反馈 - 如果您出于任何原因不需要输出(即不想显示输出),那么您可以使用这个较短的版本,减少反引号的使用,因此减少开销:

OUTPUT=0; 
while [ "$OUTPUT" = 0 ]; do 
  OUTPUT=`$cmd | grep -c somestring`;
done

BASH 函数版本还有:

function run_until () {
  OUTPUT=0; 
  while [ "$OUTPUT" = 0 ]; do 
    OUTPUT=`$1 | grep -c $2`; 
  done
}
于 2008-09-24T18:18:13.020 回答
7

我很惊讶我没有看到这里提到的简短的 Perl 单行代码:

perl -e 'do { sleep(1); $_ = `command`; print $_; } until (m/search/);'

Perl 是一种非常好的语言,可以处理这样的事情。将“命令”替换为您要重复运行的命令。将“搜索”替换为您要搜索的内容。如果要搜索带有斜线的内容,请m/search/m#search字符串替换/es#

此外,Perl 可以在许多不同的平台上运行,包括 Win32,无论您在哪里安装了 Perl,它都可以工作。只需适当地更改您的命令。

于 2008-10-02T03:39:29.247 回答
6

grep -c 99999将为匹配打印 99999 行上下文(我认为这已经足够了):

while true; do /some/command | grep expected -C 99999 && break; done

或者

until /some/command | grep expected -C 9999; do echo -n .; done

...这将打印一些漂亮的点来指示进度。

于 2008-09-25T12:35:27.343 回答
1
while (/bin/true); do
  OUTPUT=`/some/command`
  if [[ "x$OUTPUT" != "x" ]]; then
    echo $OUTPUT
    break
  fi

  sleep 1
done
于 2008-09-24T18:18:23.703 回答
1

编辑:我原来的答案是假设“一些字符串”的意思是“任何字符串”。如果你需要寻找一个特定的,Perl 可能是你最好的选择,因为在 REGEX 匹配方面几乎没有什么能比 Perl 更好。

然而,如果你因为任何原因不能使用 Perl(你可以期望 Perl 存在于大多数 Linux 发行版中,但没有人强迫用户安装它,尽管 Perl 可能不可用),你可以在grep。但是,到目前为止我看到的一些 grep 解决方案不是最理想的(它们比必要的要慢)。在这种情况下,我宁愿执行以下操作:

MATCH=''; while [[ "e$MATCH" == "e" ]]; do MATCH=`COMMAND | grep "SOME_STRING"`; done; echo $MATCH

COMMAND替换为要运行的实际命令,将SOME_STRING替换为要搜索的字符串。如果在 COMMAND 的输出中找到 SOME_STRING,则循环将停止并打印找到 SOME_STRING 的输出。

原始答案:

可能不是最好的解决方案(我不是一个好的 bash 程序员),但它会起作用:-P

RUN=''; while [[ "e$RUN" == "e" ]]; do RUN=`XXXX`; done ; echo $RUN

只需将 XXXX 替换为您的命令调用,例如尝试使用“ echo ”,它将永远不会返回(因为 echo 永远不会将任何内容打印到标准输出),但是如果您使用“ echo test ”,它将立即终止并最终打印出 test。

于 2008-09-24T18:21:39.127 回答
1
CONT=1; while [ $CONT -gt 0 ]; do $CMD | tee -a $FILE | grep -q $REGEXP; CONT=$? ; done

tee 命令可以在仍然传递数据的同时捕获管道中的标准输出,并-a使其附加到文件而不是每次都覆盖它。如果有匹配则将,grep -q否则不会向标准输出写入任何内容。是上一条命令的返回值,所以在这种情况下将是 grep 的返回值。return 01$?$CONT

于 2008-09-24T22:46:58.927 回答
0

一个简单的方法是

until `/some/command`
do
  sleep 1
done

命令周围的反引号使until测试返回某些输出,而不是测试命令的退出值。

于 2008-09-24T23:10:30.930 回答