ack와 패턴이 일치하는 파일에서만 검색


49

특정 'glob'패턴과 일치하는 파일을 통해서만 검색 할 수 있습니다 (예 : "bar * .c"라는 모든 파일에서 foo 검색). 명령

ack foo "bar*.c"

현재 디렉토리에서만 작동합니다.

참고 : find -exec로 가능하다는 것을 알고 있습니다.

find . -name "bar*.c" -type f -exec ack foo {} + 

그러나 find는 버전 제어 디렉토리를 건너 뛰지 않기 때문에 작고 간단한 ack 명령을 원합니다.


2
이해가 안됩니다 find . -name "bar*.c" -exec ack foo {} \;. 특별한 것은 없습니다 . find 's와 함께 모든 명령을 grep사용할 수 있습니다 . -exec
terdon

1
@terdon find는 버전 제어 디렉토리를 통해 검색하므로 원하지 않습니다.
compie

2
그런 다음 질문을 편집 하고 해결해야 할 제한 사항을 설명하십시오.
terdon

답변:


28

디렉토리 검색

매뉴얼 페이지에 표시된 개요를 기반으로 디렉토리를 처리 할 수 ​​있지만 스위치를 보면 패턴을 기반으로 파일 만 찾을 수는 없습니다. 이를 위해서는에 참여해야합니다 find. 이 명령 ack에는에서 --files-from=FILE파일 목록을 제공 할 수 있도록 옵션이 포함되어 있습니다 find.

개요

       ack [options] PATTERN [FILE...]
       ack -f [options] [DIRECTORY...]

용법

   --files-from=FILE
       The list of files to be searched is specified in FILE.  The list of
       files are separated by newlines.  If FILE is "-", the list is
       loaded from standard input.

--ignore-file=원하는 것을 줄 수 있지만 실제로 사용하기에는 약간의 고통 이있는 옵션이 있습니다.

   --ignore-file=FILTERTYPE:FILTERARGS
       Ignore files matching FILTERTYPE:FILTERARGS.  The filters are
       specified identically to file type filters as seen in "Defining
       your own types".

특정 유형의 파일 검색

내가 이것을 통해 생각할 수있는 유일한 다른 방법 ack--type스위치 를 사용하는 것입니다 .

   --type=[no]TYPE
       Specify the types of files to include or exclude from a search.
       TYPE is a filetype, like perl or xml.  --type=perl can also be
       specified as --perl, and --type=noperl can be done as --noperl.

       If a file is of both type "foo" and "bar", specifying --foo and
       --nobar will exclude the file, because an exclusion takes
       precedence over an inclusion.

사용 가능한 유형을 확인하려면

$ ack --help-types | grep -E "perl|cpp"

체재. 예를 들어 --type = perl 및 --perl이 모두 작동합니다. -[no] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx-[no] objcpp .mm .h-[no] perl .pl .pm .pod .t .psgi; 첫 줄은 /^#!.*\bperl/-[no] perltest와 일치합니다.

파일 이름 (* .pm, * .pl, * .t 및 * .pod)과 shebang 행을 기반으로 모든 Perl 파일을 찾으십시오.

$ ack -f --type perl 
examples/iwatch/iwatch/iwatch
examples/nytprof_perl/bad.pl

모든 C ++ 파일을 찾으십시오.

$ ack -f --type=cpp
Shared/Scanner.h
Shared/Sorter.h
Shared/DicomHelper.cpp
Shared/DicomDeviationWriter.h

bar * .c에서 foo 검색

그렇다면 원하는 것을 어떻게 달성 할 수 있습니까? 글쎄, 당신은 아마 find이것을 사용해야 할 것입니다 :

$ find adir -iname "bar*.c" | ack --files-from=- foo
adir/bar1.c
1:foo
2:foo

adir/dir1/bar1.c
1:foo
2:foo

당신은 또한 사용할 수 있습니다 ack(사용하여 파일 이름에 지정된 패턴과 일치하는 파일을 검색 할 수의 능력 -g <pattern>), 다음의 두 번째 호출이 목록을 통과 ack하여 -x또는 --files-from=-..

사용 -x:

$ ack -g '\bbar.*.c$' | ack -x foo
bar1.c
1:foo
2:foo

dir1/bar1.c
1:foo
2:foo

사용 -files-from=-:

$ ack -g '\bbar.*.c$' | ack --files-from=- foo
bar1.c
1:foo
2:foo

dir1/bar1.c
1:foo
2:foo

두 경우 모두이 정규식을 사용하려는 파일 이름과 일치합니다.

\bbar.*.c$

이것은 줄 끝 앵커를 사용하여 이름이 bar.*c끝나고 끝나는 파일과 일치합니다 . 또한 이름을 사용하여 경계 문자가 있는지 확인합니다 . 또는 예를 들어 경계 문자가 포함 된 파일의 경우 실패합니다 ..c$\b$bar.c%bar.c


1
이것은 내 질문에 대답하지 않습니다 ( "bar * .c"라는 이름의 모든 파일에서 foo 검색)
compie

1
@ compie-원하는 파일 조각을 얻는 방법을 보여줍니다. cpp파일 을 검색하려면 ack --type=cpp <string>. ack이 모든 것에 대한 자세한 내용은의 man 페이지를 참조하십시오 . 그러나 기본적으로 내가 말하는 것은 ack원하는 방식으로 검색 할 수 없다는 것입니다.
slm

1
그래서 그것은 ack요청받은 것을 할 수 없다는 것을 의미한다는 의미 에서 대답합니다.
xealits

@xealits-이 부분은 다음과 같이 답변합니다 : bar * .c에서 foo 검색 find adir -iname "bar*.c" | ack --files-from=- foo . 또는 하나의 파일 만 원할 경우 :echo "barBaz.c" | ack --files-from=- foo
alexanderbird

2
tldr; ack -g '\bbar.*.c$' | ack -x foo
chim

14

파일 형식을 알고 있으면 쉽고, ack은 많은 파일 형식을 알고 있습니다. 예를 들어 C 파일에서만 검색하려면 다음과 같이하십시오.

ack --cc 'string'

그러나 알려진 확장 중 하나가 아닌 경우 고유 한 유형을 정의해야합니다. 이것은 작동해야합니다 :

ack --type-set barc:match:/bar.+\.c/ --barc 'string'

--type-set 및 --barc가 모두 필요합니다.

(메일 링리스트에서도 도움을 준 Andy에게 감사합니다.)


1
작동하지만 find와 'ack -x'를 사용하는 것이 더 간단합니다. 나는 그것을 고수 할 것이라고 생각합니다.
compie

여기 문서에 대한 링크를 추가하면 도움이됩니다. man ack실제로 도움이되지 않으며 cc검색 할 때도 없습니다 .
YPCrumble

ack --help = types 내가 생각할 수있는 모든 것이 있습니다. 나는 주로 Python과 Ada에 사용합니다.
David Boshton

6

"ack 2의 새로운 기능은 무엇입니까?" http://beyondgrep.com/ack-2.0/

ack 2.0에서는 새로운 -x를 사용하여 ack 호출에서 다른 호출로 파일 이름을 파이프 할 수 있습니다.

ack2 -g -i filepattern | ack2 -x -w searchpattern

나는 그것을 작동시킬 수 없다.

% ack -g "*bar*.c"
Invalid regex '*bar*.c':
Quantifier follows nothing in regex; marked by <-- HERE in m/* <-- HERE bar*.c/ at ack line 314.

따라서 -g에는 정규 표현식이 필요하지만 'glob'스타일 옵션을 원합니다 ...


2
그렇습니다 -g. glob이 아닌 정규식을 사용하십시오. 정규식을로 쓸 수 있습니다 .*bar.*\.c$.
Andy Lester

2
@AndyLester 확인해 주셔서 감사합니다. ack에 대한 'glob'옵션의 아이디어가 마음에 드십니까?
compie

3

이것은 가장 빠르고 안전한 것으로 보입니다.

find . -name '*.c' | ack -x 'some string'

-x STDIN에서 검색 할 파일 목록을 읽습니다.

그러나 파일이 locate데이터베이스 에있을 가능성이 높으면 훨씬 빠릅니다.

locate --basename '*.c' | ack -x 'some thing'

또한 Locate는 구식 정규식을 받아 들일 수 있지만 약간 고통 스럽지만 c파일을 찾는 경우 필요할 수 있습니다. 예 :

locate --basename --regexp '\.\(c\|cpp\|h\|hpp\|cc\)$' |
    ack -x 'some thing'

"c, cpp, h, hpp 또는 cc로 끝나는 모든 파일 이름을 검색하십시오."


2

Ack는 glob 스타일 파일 선택을 지원하지 않습니다. 정말로 이것을 그리워하기 때문에 작은 쉘 스크립트 ackg를 만들었습니다 .

#!/bin/sh
# 'glob' support for ack
find -name "$2" -type f -exec ack "$1" {} +

이제 다음 명령을 사용할 수 있습니다 :

ackg foo "bar*.c"

그러나 참고 : 이것은 불행히도 버전 제어 디렉토리 (예 : .git)에서도 검색합니다.


2

이것은 은색 검색기 (ack-grep의 강화 된 클론) -Gag 옵션 으로 수행 할 수 있습니다 .

$ echo foo > bar_wanted.c
$ echo foo > unwanted.c
$ ag -G "bar.*\.c" foo
bar_wanted.c
1:foo

노트:

  • agPCRE 정규 표현식 구문을 사용하므로 regexp bar.*\.c대신 이어야합니다 bar*.c.
  • -G뒤에는 파일 이름으로 해석되므로 옵션이 검색어 앞에 와야합니다.

1

특정 패턴 만 원하십니까? 아니면 C 소스 파일 만 원하십니까?

모든 C 파일을 원한다면

ack --cc foo

C 파일과 NOT C 헤더 파일을 모두 사용하려면

ack --cc --no-hh foo

1

@ chim의 답변이 최고이지만 주석으로 작성되었으므로 공식 답변으로 다시 게시하고 있습니다 ...

ack -g '\bbar.*.c$' | ack -x foo

나는 당신이 길을 정규식으로 할 수 있다는 사실을 좋아합니다 ...


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.