Yalnızca ack ile bir kalıpla eşleşen dosyaları arayın


49

Yalnızca belirli bir 'glob' deseniyle eşleşen dosyaları arayabilir (örneğin: "bar * .c" adlı tüm dosyalarda foo arayabilir). Komuta

ack foo "bar*.c"

sadece geçerli dizinde çalışır.

Not: Find -exec ile mümkün olduğunu biliyorum:

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

Ancak küçük ve basit bir ack komutu istiyorum, çünkü sürüm kontrol dizinlerini bulmadı


2
Anlamıyorum, kullanmanın nesi yanlış find . -name "bar*.c" -exec ack foo {} \;? Özel bir şey yok grep, find ile birlikte herhangi bir komutu kullanabilirsiniz -exec.
terdon

1
@terdon ayrıca sürüm kontrol dizinlerini de bulur ve bunu istemiyorum.
Compie

2
Ardından sorunuzu düzenleyin ve çalışmanız gereken kısıtlamaları açıklayın.
terdon

Yanıtlar:


28

Dizinler aranıyor

Man sayfasında gösterilen özetden yola çıkarak evet, bir dizini işleyebileceğini söyleyebilirim, ancak anahtarlara bakarak sadece bir desene dayanan bir dosyayı arayamaz. Bunun için listelemek zorundasınız find. Komut ack, içerdiği --files-from=FILEdosyaların bir listesinden beslenebilmesi için seçeneği içerir find.

özet

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

kullanım

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

Orada --ignore-file=size verebilir seçenek istediğini ancak ağrı biraz aslında kullanmak gibi görünüyor.

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

Belirli dosya türlerini arama

Bunu yapmayı düşünebilmemin tek yolu anahtarını ackkullanmak --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.

Hangi türlerin mevcut olduğunu görmek için:

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

biçim. Örneğin, --type = perl ve --perl işlevi. - [no] cpp .cpp .cc .cxx .m. ilk satır /^#!.*\bperl/ - [no] perltest .t ile eşleşir.

Örnekler

Dosya adını (* .pm, * .pl, * .t ve * .pod) ve shebang satırını temel alarak tüm Perl dosyalarını bulun.

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

Tüm C ++ dosyalarını bul:

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

Barda foo aranıyor * .c

Öyleyse istediğini nasıl başarabilirsin? Bunu findyapmak için muhtemelen kullanmanız gerekecek :

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

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

Ayrıca ack, belirli bir şablonla dosya adlarında (kullanarak -g <pattern>) eşleşen dosyaları arama özelliğini kullanabilir ve ardından bu listeyi veya tuşlarını ackkullanarak ikinci bir çağrıya geçirebilirsiniz .-x--files-from=-

Kullanarak -x:

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

dir1/bar1.c
1:foo
2:foo

Kullanarak -files-from=-:

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

dir1/bar1.c
1:foo
2:foo

Her iki durumda da, bu regex'i kullanmak istediğiniz dosya isimleriyle eşleştiriyoruz:

\bbar.*.c$

Bu , satır sonu bağlantısının kullanımından bar.*csonra adı ve sonu olan dosyalarla eşleşir ,. Ayrıca, adların kullanımda sınır karaktere sahip olduğundan emin olmak istiyoruz . Bu, örneğin veya gibi sınır karakterleri içeren dosyalar için başarısız olur ..c$\b$bar.c%bar.c


1
Bu sorumu cevaplamıyor ("bar * .c" adlı tüm dosyalarda foo arayın)
compie

1
@compie - İstediğiniz dosyaların bir diliminin nasıl alınacağını size gösterdiğimi gösteriyor. cppDosyaları aramak için ack --type=cpp <string>. ackBu konuda daha fazla bilgi için man sayfasına bakın . Ama temelde size söylediğim şey, ackistediğiniz şekilde arama yapamayacağınızdır .
slm

1
bu yüzden, sorulanı ackyapamayacağını gösteren anlamıyla cevap veriyor .
Xealits

@ xealits - bu kısım cevap verir: * .c çubuğunda foo aranıyor find adir -iname "bar*.c" | ack --files-from=- foo . Veya, yalnızca bir dosya istiyorsanız:echo "barBaz.c" | ack --files-from=- foo
alexanderbird

2
TLDR; ack -g '\bbar.*.c$' | ack -x foo
şimşir

14

Dosya türü biliniyorsa kolaydır ve ack birçok dosya türünü bilir. Dolayısıyla, örneğin, yalnızca C dosyalarında arama yapmak istiyorsanız, yapabildiğinizden daha fazlasını yapın:

ack --cc 'string'

Ancak bilinen uzantılardan biri değilse, kendi türünüzü tanımlamanız gerekir. Bu çalışmalı:

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

- - type-set ve --barc öğelerine ihtiyacınız olduğunu unutmayın.

(E-posta listesinde buna yardımcı olan Andy'ye teşekkürler.)


1
Tamam, işe yarar ancak find ve 'ack -x' komutunu kullanmak daha kolaydır. Sanırım buna bağlı kalacağım.
Compie

Buraya dokümanlar için bir bağlantı eklemek yararlı olacaktır. man ackGerçekten yardım etmiyor ve ccaradığımda da yok.
YPCrumble

ack --help = tipleri Orada düşünebileceğim her şey var. Çoğunlukla Python ve Ada için kullanıyorum.
David Boshton

6

"Ack 2'deki yenilikler neler?" http://beyondgrep.com/ack-2.0/

ack 2.0 ile, new -x komutunu, dosya adlarını bir ack çağrısından diğerine aktarmak için kullanabilirsiniz.

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

Sadece çalışmasını sağlayamıyorum:

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

Öyle görünüyor ki -g bir regex'e ihtiyaç duyuyor, ben 'glob' tarzı bir seçenek istiyorum


2
Evet, -gbir regex alır, bir küre değil. Regex'inizi olarak yazabilirsiniz .*bar.*\.c$.
Andy Lester

2
@AndyLester Onaylamak için teşekkürler. Ack için 'glob' seçeneği fikrini beğendiniz mi?
Compie

3

Bu en hızlı ve en güvenli gibi görünüyor:

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

-x STDIN'den aranacak dosyaların listesini okuyun.

Ancak, dosya locateveritabanınızda olması muhtemelse , bu daha da hızlı olacaktır:

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

Bul, ayrıca eski okul düzenli ifadelerini de kabul edebilir, biraz acı verici, ancak cdosya arıyorsanız , gerekli olabilir. Örneğin

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

Bu sadece çevirir: "c, cpp, h, hpp veya cc ile biten tüm dosya isimlerini ara."


2

Ack, glob stili dosya seçimini desteklemez. Bunu gerçekten özlediğimden beri ackg adlı küçük bir kabuk betiği oluşturdum :

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

Şimdi komutu kullanabilirsiniz:

ackg foo "bar*.c"

Ancak not: Bu ne yazık ki sürüm kontrol dirslerinde de arama yapacaktır (örneğin: .git).


2

Bu ile yapılabilir -Gseçeneği ag, gümüş arama yapan (ack-grep gelişmiş bir klon).

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

Notlar:

  • agPCRE normal ifade sözdizimini kullanır , bu nedenle regexp bar.*\.cyerine olmalıdır bar*.c.
  • -GOpsiyon bundan sonra her şey bir dosya adı olarak yorumlanır olarak, arama terimini öncesinde bulunması gerekir.

1

Yalnızca belirli bir kalıp mı istiyorsunuz, yoksa sadece C kaynak dosyalarını mı istiyorsunuz?

Tüm C dosyalarını istiyorsanız,

ack --cc foo

Tüm C dosyalarını ve NOT C başlık dosyalarını kullanmak istiyorsanız

ack --cc --no-hh foo

1

@chim 'in cevabı en iyisidir, fakat yorum olarak yazılmıştır, bu yüzden resmi bir cevap olarak tekrar gönderiyorum ...

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

Yolunu düzeltebileceğin gerçeğini seviyorum.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.