Подтвердить что ты не робот

Как совместить один раз в файле в grep?

Есть ли опция 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 рассматривает его как глобальный счетчик совпадений

4b9b3361

Ответ 1

Я думаю, вы можете просто сделать что-то вроде

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

например. выберите первое совпадение из каждого файла и выберите не более двух совпадений.

Обратите внимание, что для этого grep требуется -m обрабатывать -m как ограничение на соответствие каждому файлу; GNU grep делает это, но BSD grep, по-видимому, рассматривает его как ограничение глобального соответствия.

Ответ 2

Итак, используя grep, вам просто нужна опция -l, --files-with-matches.

Все ответы на find, awk или сценарии оболочки находятся вдали от вопроса.

Ответ 3

Я бы сделал это вместо 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

Ответ 4

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

find -exec запускает команду один раз для каждого сопоставленного файла (если вы не используете + вместо \;, что заставляет его действовать как xargs).

Ответ 5

с помощью find и xargs. найти каждый файл. coffee и excute -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

add -m1

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

Ответ 6

Вы можете сделать это легко в 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. Они не сильно отличаются.

Вы можете сделать рекурсивную часть в Perl, используя File:: Find или использовать find для кормления файлов.

find /some/path -name '*.coffee' -print0 | xargs -0 perl /path/to/your/program