66

是否有任何 grep 选项可以让我控制匹配的总数,但在每个文件的第一次匹配时停止?

例子:

如果我这样做,grep -ri --include '*.coffee' 're' .我会得到:

./app.coffee:express = require 'express'
./app.coffee:passport = require 'passport'
./app.coffee:BrowserIDStrategy = require('passport-browserid').Strategy
./app.coffee:app = express()
./config.coffee:    session_secret: 'nyan cat'

如果我这样做grep -ri -m2 --include '*.coffee' 're' .,我会得到这个:

./app.coffee:config = require './config'
./app.coffee:passport = require 'passport'

但是,我真正想要的是这个输出:

./app.coffee:express = require 'express'
./config.coffee:    session_secret: 'nyan cat'

这样做-m1不起作用,因为我得到了这个grep -ri -m1 --include '*.coffee' 're' .

./app.coffee:express = require 'express'

尝试不使用 grep 例如这find . -name '*.coffee' -exec awk '/re/ {print;exit}' {} \;产生了:

config = require './config'
    session_secret: 'nyan cat'

更新:如下所述,GNU grep-m选项将每个文件视为计数,而-m对于 BSD grep 将其视为全局匹配计数

4

6 回答 6

79

因此,使用grep,您只需要选项-l, --files-with-matches

所有关于find,awk或 shell 脚本的答案都与问题无关。

于 2014-03-25T10:50:27.747 回答
42

我认为你可以做类似的事情

grep -ri -m1 --include '*.coffee' 're' . | head -n 2

例如从每个文件中选择第一个匹配项,最多选择两个匹配项。

请注意,这需要您grep将其-m视为每个文件的匹配限制;GNUgrep确实这样做了,但 BSDgrep显然将其视为全局匹配限制。

于 2012-10-11T02:53:37.227 回答
4

我会这样做awk

find . -name \*.coffee -exec awk '/re/ {print FILENAME ":" $0;exit}' {} \;

如果你不需要递归,你可以用 awk 来做:

awk '/re/ {print FILENAME ":" $0;nextfile}' *.coffee

或者,如果您使用的是足够电流的 bash,则可以使用 globstar:

shopt -s globstar
awk '/re/ {print FILENAME ":" $0;nextfile}' **/*.coffee
于 2012-10-11T03:11:22.383 回答
2

使用查找和 xargs。找到每个 .coffee 文件并对每个文件执行 -m1 grep

find . -print0 -name '*.coffee'|xargs -0 grep -m1 -ri 're'

没有 -m1 的测试

linux# find . -name '*.txt'|xargs grep -ri 'oyss'
./test1.txt:oyss
./test1.txt:oyss1
./test1.txt:oyss2
./test2.txt:oyss1
./test2.txt:oyss2
./test2.txt:oyss3

添加-m1

linux# find . -name '*.txt'|xargs grep -m1 -ri 'oyss'
./test1.txt:oyss
./test2.txt:oyss1
于 2012-10-11T03:38:57.670 回答
2

find . -name \*.coffee -exec grep -m1 -i 're' {} \;

find 的 -exec 选项为每个匹配的文件运行一次命令(除非您使用+而不是\;,这使得它的行为类似于 xargs)。

于 2012-10-11T04:56:17.507 回答
0

你可以在 perl 中轻松地做到这一点,而且没有混乱的跨平台问题!

use strict;
use warnings;
use autodie;

my $match = shift;

# Compile the match so it will run faster
my $match_re = qr{$match};

FILES: for my $file (@ARGV) {
    open my $fh, "<", $file;

    FILE: while(my $line = <$fh>) {
        chomp $line;

        if( $line =~ $match_re ) {
            print "$file: $line\n";
            last FILE;
        }
    }
}

唯一的区别是你必须使用 Perl 风格的正则表达式而不是 GNU 风格。 他们没有太大的不同

您可以使用File::Find在 Perl 中执行递归部分,或使用findfeed it 文件。

find /some/path -name '*.coffee' -print0 | xargs -0 perl /path/to/your/program
于 2012-10-11T03:37:34.813 回答