Cari hanya di file yang cocok dengan pola dengan ack


49

Dapat melakukan pencarian hanya melalui file yang cocok dengan pola 'glob' tertentu (misalnya: mencari foo di semua file bernama "bar * .c"). Perintah

ack foo "bar*.c"

hanya berfungsi di direktori saat ini.

Catatan: Saya tahu ini mungkin dengan find -exec:

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

Tapi saya ingin perintah ack kecil dan sederhana, karena find tidak melewatkan direktori kontrol versi.


2
Saya tidak mengerti, apa yang salah dengan menggunakan find . -name "bar*.c" -exec ack foo {} \;? Tidak ada yang istimewa grep, Anda dapat menggunakan perintah apa pun dengan find's -exec.
terdon

1
@terdon menemukan juga mencari melalui direktori kontrol versi dan saya tidak menginginkannya.
compie

2
Kemudian silakan edit pertanyaan Anda dan jelaskan batasan yang perlu Anda selesaikan.
terdon

Jawaban:


28

Mencari direktori

Berdasarkan sinopsis yang diperlihatkan dalam halaman manual saya akan mengatakan ya itu dapat memproses direktori, tetapi melihat sakelar itu tidak dapat mencari hanya file berdasarkan suatu pola. Untuk itu Anda harus mendaftar find. Perintah acktidak menyertakan opsi --files-from=FILEsehingga dapat diumpankan daftar file dari find.

ringkasan

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

pemakaian

   --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.

Ada --ignore-file=opsi yang dapat memberi Anda apa yang Anda inginkan tetapi tampaknya sedikit sakit untuk benar-benar digunakan.

   --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".

Mencari jenis file tertentu

Satu-satunya cara lain yang bisa saya bayangkan untuk melakukan hal ini ackadalah dengan menggunakan --typesakelarnya:

   --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.

Untuk melihat jenis apa yang tersedia:

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

format. Misalnya, keduanya --type = perl dan --perl berfungsi. - [tidak] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx - [tidak] objcpp .mm .h - [tidak] perl .pl .pm .pod .t .psgi; baris pertama cocok /^#!.* \bperl/ - [no] perltest .t

Contohnya

Temukan semua file Perl, berdasarkan nama file (* .pm, * .pl, * .t dan * .pod) dan baris shebang.

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

Temukan semua file C ++:

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

Mencari foo di bilah * .c

Jadi, bagaimana Anda bisa mencapai apa yang Anda inginkan? Mungkin Anda harus menggunakannya finduntuk melakukan ini:

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

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

Anda juga dapat menggunakan ackkemampuan untuk mencari file yang cocok dengan pola yang diberikan dalam nama file mereka (menggunakan -g <pattern>), dan kemudian meneruskan daftar ini ke doa kedua ackmenggunakan -xatau --files-from=-..

Menggunakan -x:

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

dir1/bar1.c
1:foo
2:foo

Menggunakan -files-from=-:

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

dir1/bar1.c
1:foo
2:foo

Dalam kedua kasus kami mencocokkan nama file yang Anda inginkan menggunakan regex ini:

\bbar.*.c$

Ini cocok dengan file yang namanya bar.*cdan berakhir setelah .cmenggunakan ujung jangkar $,. Kami juga berupaya memastikan bahwa nama-nama tersebut menggunakan karakter batas \b. Ini akan gagal untuk file yang berisi karakter batas seperti $bar.catau %bar.cmisalnya.


1
Ini tidak menjawab pertanyaan saya (mencari foo di semua file bernama "bar * .c")
compie

1
@compie - benar-benar dalam arti saya menunjukkan kepada Anda cara mendapatkan sepotong file yang Anda inginkan. Untuk mencari cppfile ack --type=cpp <string>. Lihat ackhalaman manual untuk lebih lanjut tentang semua ini. Tetapi pada dasarnya saya memberi tahu Anda bahwa Anda tidak dapat mencari menggunakan ackcara yang Anda inginkan.
slm

1
jadi itu menjawab dalam arti bahwa itu menunjukkan acktidak dapat melakukan apa yang diminta.
xealits

@xealits - bagian ini menjawabnya: Mencari foo di bar * .c find adir -iname "bar*.c" | ack --files-from=- foo . Atau, jika Anda hanya ingin satu file:echo "barBaz.c" | ack --files-from=- foo
alexanderbird

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

14

Sangat mudah jika jenis file diketahui, dan ACK tahu banyak jenis file. Jadi, jika, misalnya, Anda hanya ingin mencari dalam file C, daripada yang dapat Anda lakukan:

ack --cc 'string'

Tetapi jika itu bukan salah satu dari ekstensi yang dikenal, Anda perlu mendefinisikan tipe Anda sendiri. Ini seharusnya bekerja:

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

Perhatikan bahwa Anda membutuhkan --type-set dan --barc.

(Terima kasih kepada Andy, yang juga membantu dengan ini di milis.)


1
Ok itu berfungsi tetapi menggunakan find dan 'ack -x' lebih sederhana. Saya pikir saya akan tetap dengan itu.
compie

Menambahkan tautan ke dokumen di sini akan sangat membantu. man acktidak benar-benar membantu dan tidak memiliki ccketika saya mencari itu.
YPCrumble

ack --help = types Ada yang bisa saya pikirkan di sana. Saya kebanyakan menggunakannya untuk Python dan Ada.
David Boshton

6

"Apa yang baru dalam ack 2?" http://beyondgrep.com/ack-2.0/

dengan ack 2.0, Anda dapat menggunakan -x baru untuk menyalurkan nama file dari satu permintaan ack ke yang lain.

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

Hanya saya yang tidak bisa menjalankannya:

% 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.

Jadi sepertinya -g membutuhkan regex, sementara saya ingin opsi gaya 'glob' ...


2
Ya, -gambil regex, bukan glob. Anda dapat menulis regex Anda sebagai .*bar.*\.c$.
Andy Lester

2
@AndyLester Terima kasih telah mengonfirmasi. Apakah Anda menyukai gagasan opsi 'glob' untuk ack?
compie

4

Ini tampaknya yang tercepat dan teraman:

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

-x Baca daftar file yang akan dicari dari STDIN.

Namun, jika file tersebut kemungkinan ada di locatedatabase Anda , ini akan lebih cepat:

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

Locate juga dapat menerima ekspresi reguler old-school, sedikit menyakitkan, tetapi jika Anda mencari cfile, mungkin diperlukan. misalnya

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

Itu hanya menerjemahkan ke: "cari semua nama file yang berakhiran c, cpp, h, hpp atau cc."


2

Ack tidak mendukung pemilihan file gaya glob. Karena saya sangat merindukan ini, saya membuat ackg script shell kecil :

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

Sekarang Anda dapat menggunakan perintah:

ackg foo "bar*.c"

Tetapi perhatikan: sayangnya ini juga akan mencari di dir kontrol versi (misalnya: .git).


2

Ini dapat dilakukan dengan -Gopsi ag, pencari perak (klon yang disempurnakan dari ack-grep).

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

Catatan:

  • agmenggunakan sintaks ekspresi reguler PCRE , jadi regexp harus bar.*\.cbukan bar*.c.
  • The -Gpilihan perlu mendahului istilah pencarian, sebagai sesuatu setelah itu ditafsirkan sebagai nama file.

1

Apakah Anda hanya menginginkan pola tertentu, atau Anda hanya ingin file sumber C?

Jika Anda ingin semua file C, gunakan

ack --cc foo

Jika Anda ingin semua file C dan BUKAN file header gunakan

ack --cc --no-hh foo

1

Jawaban @ chim adalah yang terbaik, tetapi ditulis sebagai komentar jadi saya memposting ulang sebagai jawaban formal ...

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

Saya suka fakta bahwa Anda dapat regex jalan ...


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.