İki farklı kelimenin bulunduğu dosyalar nasıl aranır?


14

Aynı dosyada iki kelime örneği bulunan dosyaları aramak için bir yol arıyorum. Bu noktaya kadar aramalarımı gerçekleştirmek için aşağıdakileri kullanıyorum:

find . -exec grep -l "FIND ME" {} \;

Ben karşılaşıyorum sorun "BUL" ve "ME" arasında tam olarak bir boşluk yoksa, arama sonucu dosyayı vermez olmasıdır. "BUL" ve "ME" kelimelerinin her ikisinin de "BULUN" yerine bir dosyada bulunduğu eski arama dizesini nasıl uyarlayabilirim?

AIX kullanıyorum.


1
Kelimeler dosyanın herhangi bir yerinde var mı, yoksa her zaman aynı satırda mı?
Sobrique

Niyet aynı çizgiydi.
Chad Harrison

Bir alternatif, eğer kelimeler aynı grep -Eegrep+;+
satırdaysa

Yanıtlar:


21

GNU araçlarıyla:

find . -type f  -exec grep -lZ FIND {} + | xargs -r0 grep -l ME

Standart olarak şunları yapabilirsiniz:

find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;

Ancak bu, dosya başına iki greft çalıştırır. grepDosya adlarında herhangi bir karaktere izin verirken bu kadar çok s'yi çalıştırmayı ve yine de taşınabilir olmayı önlemek için şunları yapabilirsiniz:

convert_to_xargs() {
  sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
    {
      if (NR > 1) {
        printf "%s", line
        if (!index($0, "//")) printf "\\"
        print ""
      }
      line = $0
    }'
    END { print line }'
}

find .//. -type f |
  convert_to_xargs |
  xargs grep -l FIND |
  convert_to_xargs |
  xargs grep -l ME

Çıkışı, tek, çift tırnak işaretleri ve ters eğik çizgilerin olabileceği ayrılmış bir kelime listesi olan findxargs (boş bir boşluk (SPC / TAB / NL ve yerel ayarınızdaki diğer boşluklar) ile ilgili bir biçime dönüştürmektir. xargsboşlukları ve birbirleri kaçış).

Genellikle find -print, dosya adlarını yeni satır karakteriyle ayırdığı ve dosya adlarında bulunan yeni satır karakterlerinden çıkmadığı için çıktısını sonradan işleyemezsiniz . Örneğin:

./a
./b

Bunun bbir dizinde adlandırılan bir dosya a<NL>.mı yoksa iki dosya ave mı olduğunu bilmenin bir yolu yok b.

Kullanarak .//., //başka bir şekilde çıktı olarak bir dosya yolunda görünemediğinden find(boş bir ada sahip bir dizin diye bir şey /olmadığı ve dosya adında izin verilmediği için), içeren bir satır görürsek //, yeni bir dosya adının ilk satırı. Bu awkkomutu, bu satırlardan önce gelen tüm yeni satır karakterlerinden kaçmak için kullanabiliriz .

Yukarıdaki örneği alırsak find, ilk durumda çıktı alır (bir dosya):

.//a
./b

Hangi awk kaçar:

.//a\
./b

Bu xargsonu tek bir argüman olarak görüyor. Ve ikinci durumda (iki dosya):

.//a
.//b

Hangi awkolduğu gibi xargsbırakılır , böylece iki argüman görür.


Neden kullanmaz find ... -print0ve grep --nullbunun yerine?
Haziran'da razzed

@razzed, ne demek istediğinden emin değilim. grep --null(aka -Z) ilkinde kullanılır ancak bir GNU oluşumudur. -print0(başka bir GNU uzantısı) burada yardımcı olmaz.
Stéphane Chazelas

Teşekkürler. Kabuk kodunuzu arama dizinini komut satırından bağımsız değişken olarak alan bir komut dosyasına sarmak istiyorum. .//.Henüz ne anlama geldiğinden emin değilim ve bunu komut satırından bir argümanı kabul etmek için nasıl değiştirebileceğimi merak ediyorum, öyle $1mi?
Tim

Teşekkürler. Emriniz, bu kullanmak gerekir -print0ile findve -0ile xargs?
Tim

@Zaman, ne demek istediğinden emin değilim. find -print0Cevabımda hiçbir yerde kullanmıyorum .
Stéphane Chazelas

8

Dosyalar tek dizininde yer alıyor ve isimlerini alanı sekmesini, yeni satır, içermiyorsa *, ?ne de [karakterleri ve başlamıyoruz -ne de .bu ME içeren dosyaların bir listesini alacak, o zaman olanları o aşağı daraltmak o ayrıca FIND içerir.

grep -l FIND `grep -l ME *`

BU daha upvotes ihtiyacı var !! "Kabul edilen" cevaptan çok daha zarif. Benim için çalıştı.
roblogic

Sadece grep -l CategoryLinearAxis `grep -l labelJsFunction *`her iki özelliği de olan dosyaları ararken yaptım . Bunu yapmak için ne mükemmel bir yol. +1
WEBjuju

3

İle awkde çalıştırabilir:

find . -type f  -exec awk 'BEGIN{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; END{if (cx > 0 && cy > 0) print FILENAME}' {} \;

Bu kullanır cxve cyeşleşen hatlar için saymak FINDve sırasıyla ME. In ENDblokta, her iki sayaçları> 0 ise, bu yazdırır FILENAME.
Bu, aşağıdakilerle daha hızlı / daha verimli olacaktır gnu awk:

find . -type f  -exec gawk 'BEGINFILE{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; ENDFILE{if (cx > 0 && cy > 0) print FILENAME}' {} +

2

Veya bunu kullanın egrep -eveya grep -Ebeğenin:

find . -type f -exec egrep -le '(ME.*FIND|FIND.*ME)' {} \;

veya

find . -type f -exec grep -lE '(ME.*FIND|FIND.*ME)' {} +

Marka +, find (destekleniyorsa) edilmekte olan komuta bağımsız değişken olarak birden çok dosya (yol) adı ekler -exec. Bu, işlemleri kaydeder ve bulunan \;her dosya için komutu bir kez çağırandan çok daha hızlıdır .

-type f Bir dizinde açılmayı önlemek için yalnızca dosyalarla eşleşir.

'(ME.*FIND|FIND.*ME)'"ME" ve ardından "BUL" veya "BUL" ve ardından "ME" içeren herhangi bir satırla eşleşen normal bir ifadedir. (kabuğun özel karakterleri yorumlamasını önlemek için tek tırnak işareti).

Büyük / küçük harfe duyarlı olmamak -iiçin grepkomuta a ekleyin .

Yalnızca "BUL" öğesinin "ME" den önce geldiği satırları eşleştirmek için kullanın 'FIND.*ME'.

Sözcükler arasında boşluk (1 veya daha fazla, ancak başka hiçbir şey) gerektirmez: 'FIND +ME'

Sözcükler arasında boşluklara (0 veya daha fazla, ancak hiçbir şey) izin vermek için: 'FIND *ME'

Kombinasyonlar düzenli ifadelerle sınırsızdır ve yalnızca bir kerede satır bazında eşleştirme ile ilgileniyorsanız, egrep çok güçlüdür.


Greplerin çoğu "-r" yi desteklemiyor mu? Bu, "bul" işlevini ortadan kaldırır, ancak aranan ağaçta yuvalar veya diğer düz olmayan dosyalar olabilir.
çalıntı annem

OP, AIX kullanıyor ve findsoru vardı .
MattBianco

0

Kabul edilen cevaba bakıldığında olması gerekenden daha karmaşık görünüyor. GNU sürümleri findve grepve xargsdestek BOş sonlandırılmış dizeleri. Bu kadar basit:

find . -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l ME

İstediğiniz finddosyalara filtre uygulamak için komutunuzu değiştirebilirsiniz ve herhangi bir karakter içeren dosya adlarıyla çalışır; sedayrıştırma ek karmaşıklığı olmadan . Dosyaları daha fazla işlemek istiyorsanız --null, sonuncuya bir tane daha ekleyingrep

find . -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l --null ME | xargs -0 echo

Ve bir işlev olarak:

find_strings() {
    find . -type f -print0 | xargs -0 grep -l --null "$1" | xargs -0 grep -l "$2"
}

Açıkçası, bu araçların GNU sürümlerini çalıştırmıyorsanız kabul edilen cevabı kullanın.


1
--null, --print0, -0Hepsi GNU oluşumudur. Bazıları günümüzde diğer uygulamalarda bulunmasına rağmen, hala taşınabilir değiller ve POSIX veya Unix standardında değiller.
Stéphane Chazelas
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.