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