grep dosyasında farklı satırlarda birden çok dizge için (yani satır tabanlı arama değil, tüm dosya)?


85

Ben kelimeleri içeren dosyalar için yazılması istiyorum Dansk, Svenskaya Norsk kullanışlı dönüş kodu ile, herhangi bir hat üzerinde (dizeleri yer aldığını bilgilere sahip Gerçekten sadece benzerleri gibi, benim bir astar ayrıca daha sonra bu biraz gider).

İçinde şu satırlar olan birçok dosyam var:

Disc Title: unknown
Title: 01, Length: 01:33:37.000 Chapters: 33, Cells: 31, Audio streams: 04, Subpictures: 20
        Subtitle: 01, Language: ar - Arabic, Content: Undefined, Stream id: 0x20, 
        Subtitle: 02, Language: bg - Bulgarian, Content: Undefined, Stream id: 0x21, 
        Subtitle: 03, Language: cs - Czech, Content: Undefined, Stream id: 0x22, 
        Subtitle: 04, Language: da - Dansk, Content: Undefined, Stream id: 0x23, 
        Subtitle: 05, Language: de - Deutsch, Content: Undefined, Stream id: 0x24, 
(...)

İşte istediğim şeyin sözde kodu:

for all files in directory;
 if file contains "Dansk" AND "Norsk" AND "Svenska" then
 then echo the filename
end

Bunu yapmanın en iyi yolu nedir? Tek hatta yapılabilir mi?

Yanıtlar:


89

Kullanabilirsiniz:

grep -l Dansk * | xargs grep -l Norsk | xargs grep -l Svenska

Gizli dosyalarda da bulmak istiyorsanız:

grep -l Dansk .* | xargs grep -l Norsk | xargs grep -l Svenska

Akıllı çözüm; nota bir şey (genel olarak konuşursak; neyi OP soruyordu ilgili olmayan) genel olmasıdır çıkış kodu olacaktır 0 bile (kavramsal) arızası durumunda. Bu nedenle, başarısızlığa karşı başarıyı belirlemekle ilgileniyorsanız, stdout çıktısının boş olup olmadığını incelemeniz veya bunun yerine @ EddSteel'in yaklaşımını kullanmanız gerekir.
mklement0

@mklement: Bash'de, PIPESTATUSdizi bir ardışık düzenin üyelerinin çıkış değerlerini içerir.
Dennis Williamson

@DennisWilliamson Bunu bilmek güzel, teşekkürler. Diğer bir seçenek de pipefailkabuk seçeneğini shopt -so pipefail
açmaktır

4
Sen kullanmak isteyebilirsiniz grep -Zve xargs -0Dosya adlarınız boşluk içerebilir eğer.
Ben Challenor

1
Bu, çok sayıda dosyanız varsa "bağımsız değişken listesi çok uzun" hatalarına neden olabilir.
AnnanFay

23

Sadece bash ve grep kullanmanın başka bir yolu:

Tek bir dosya 'test.txt' için:

  grep -q Dansk test.txt && grep -q Norsk test.txt && grep -l Svenska test.txt

test.txtDosya üçünü de içeriyorsa (herhangi bir kombinasyonda) yazdırılır . İlk iki greps hiçbir şey ( -q) yazdırmaz ve sonuncusu yalnızca diğer ikisi geçerse dosyayı yazdırır.

Dizindeki her dosya için yapmak istiyorsanız:

   f in * için; do grep -q Dansk $ f && grep -q Norsk $ f && grep -l Svenska $ f; bitti

ancak grep'i 3 kez çalıştırmaya gerek yoktur.
kurumi

1
Kalıpları -e ile birleştirebileceğinizi biliyorum, ancak tek başına grep'te bir bağlantı kurmanın bir yolunu göremedim.
Edd Steel

1
Harika; re for f ...: "$f"sadece $fgömülü boşluklara sahip dosya adlarının vb. doğru bir şekilde işlendiğinden emin olmak yerine (çift tırnak) kullanın .
mklement 0

Bu yaklaşımın @ vmpstr'lere göre avantajı, çıkış kodunun bulunan tüm arama terimlerini doğru şekilde yansıtmasıdır.
mklement 0

19
grep –irl word1 * | grep –il word2 `cat -` | grep –il word3 `cat -`
  • -i arama durumunu duyarsız hale getirir
  • -r klasörler aracılığıyla dosya aramayı yinelemeli hale getirir
  • -l Bulunan sözcüğün bulunduğu dosyaların listesini çıkarır
  • cat - bir sonraki grep'in listeye aktarılan dosyalara bakmasına neden olur.

1
bu en basit ve en anlaşılır cevap, çok yardımcı oldu teşekkürler!
majick

9

Dosyadaki farklı satırlarda birden çok dizge için grep nasıl yapılır (Boru sembolünü kullanın):

for file in *;do 
   test $(grep -E 'Dansk|Norsk|Svenska' $file | wc -l) -ge 3 && echo $file
done

Notlar:

  1. ""Grep'inizde çift ​​tırnak kullanırsanız , borudan şu şekilde kaçmanız gerekir: \|Dansk, Norsk ve Svenska'yı aramak için.

  2. Bir satırın yalnızca bir dile sahip olduğunu varsayar.

İzlenecek yol: http://www.cyberciti.biz/faq/howto-use-grep-command-in-linux-unix/


Dansk Norsk ve Svenska aynı satırda görünseler bu başarısız olmaz mıydı?
vmpstr

Evet, bu durumda başarısız olur. Dillerin her satırda bir tane göründüğünü varsaydım.
Damodharan R

Sadece sahip olsaydım da dosyalardı Norsk , ancak üç farklı satırda da dosyalardı.
Benjamin W.

6

Bunu ack ile gerçekten kolayca yapabilirsiniz :

ack -l 'cats' | ack -xl 'dogs'
  • -l: dosyaların bir listesini döndür
  • -x: dosyaları STDIN'den (önceki arama) alın ve yalnızca bu dosyaları arayın

Ve sadece istediğiniz dosyaları elde edene kadar boruyu tutabilirsiniz.


Bunu denediğimde diyor Unknown option: x. Bu x bayrağını destekleyen belirli bir ack sürümü var mı?
Hassan

4
awk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print "0" }' 

daha sonra geri dönüş değerini kabuk ile yakalayabilirsiniz

Ruby'niz varsa (1.9+)

ruby -0777 -ne 'print if /Dansk/ and /Norsk/ and /Svenka/' file

1
awk END cümlenizde, muhtemelen şunu isteyeceksiniz: if (a && b && c) {exit 0} else {exit 1}veya daha kısacaexit !(a && b && c)
glenn jackman

yakut çözümünüz doğru görünmüyor. bu yalnızca tüm arama sözcüklerini içeren paragrafları yazdırır. soru şudur: dosya (bir bütün olarak), hepsi aynı paragrafta görünmese bile tüm kelimeleri içeriyor mu?
glenn jackman

Teşekkürler. tüm dosya gerekliyse değiştirildi, sonra kullanmak zorunda -0777
kurumi

4

Bu, birden çok dosyada birden çok kelimeyi arar:

egrep 'abc|xyz' file1 file2 ..filen 

2
Her iki dizeye sahip dosyaları bulmanın yanı sıra, bu aynı zamanda tek başına 'abc' VEYA 'xyz' içeren dosyaları da bulacaktır. Sanırım OP, 'abc' VE 'xyz' içeren dosyalar istiyordu.
Chris Warth

3

Basitçe:

grep 'word1\|word2\|word3' *

daha fazla bilgi için bu gönderiye bakın


Ben eklersiniz -lbayrağı, ama bunun dışında, bu cevabı ben bir şey eksik sürece, bana en dolaysız görünüyor.
xdhmoore

Evet, tüm verileri birden çok boru ve filtrede
işlemediğiniz için

3
Soru, üç terimi de içeren dosyaları döndüren bir ifadeyi sorar; bu, üçünden herhangi birini içeren (üçünün tümü yerine) satırları (dosya adları yerine) döndürür.
Benjamin W.

2

Bu, glenn jackman'ın ve kurumi'nin yanıtlarının bir karışımı olup, rastgele sayıda sabit kelime veya sabit bir dizi normal ifade yerine rastgele bir sayıda normal ifadeye izin verir.

#!/usr/bin/awk -f
# by Dennis Williamson - 2011-01-25

BEGIN {
    for (i=ARGC-2; i>=1; i--) {
        patterns[ARGV[i]] = 0;
        delete ARGV[i];
    }
}

{
    for (p in patterns)
        if ($0 ~ p)
            matches[p] = 1
            # print    # the matching line could be printed
}

END {
    for (p in patterns) {
        if (matches[p] != 1)
            exit 1
    }
}

Şöyle çalıştırın:

./multigrep.awk Dansk Norsk Svenska 'Language: .. - A.*c' dvdfile.dat

2

İşte benim için iyi sonuç veren şey:

find . -path '*/.svn' -prune -o -type f -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh
./another/path/to/file2.txt
./blah/foo.php

Bu üçüyle .sh dosyalarını bulmak isteseydim, şunu kullanabilirdim:

find . -path '*/.svn' -prune -o -type f -name "*.sh" -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh

1

@ Kurumi'nin awk cevabını genişletecek olursak, işte bir bash işlevi:

all_word_search() {
    gawk '
        BEGIN {
            for (i=ARGC-2; i>=1; i--) {
                search_terms[ARGV[i]] = 0;
                ARGV[i] = ARGV[i+1];
                delete ARGV[i+1];
            }
        }
        {
            for (i=1;i<=NF; i++) 
                if ($i in search_terms) 
                    search_terms[$1] = 1
        }
        END {
            for (word in search_terms) 
                if (search_terms[word] == 0) 
                    exit 1
        }
    ' "$@"
    return $?
}

Kullanım:

if all_word_search Dansk Norsk Svenska filename; then
    echo "all words found"
else
    echo "not all words found"
fi

1

Bunu iki adımda yaptım. Tek bir dosyada csv dosyalarının bir listesini yapın Bu sayfanın yorumlarının yardımıyla ihtiyacım olanı elde etmek için iki komut dosyası içermeyen adım yaptım. Sadece terminale yazın:

$ find /csv/file/dir -name '*.csv' > csv_list.txt
$ grep -q Svenska `cat csv_list.txt` && grep -q Norsk `cat csv_list.txt` && grep -l Dansk `cat csv_list.txt`

tam olarak ihtiyacım olan şeyi yaptı - üç kelimeyi de içeren dosya adları yazdırın.

Ayrıca şu sembollere de dikkat et `' "


1

Yalnızca iki arama terimine ihtiyacınız varsa, tartışmasız en okunaklı yaklaşım, her aramayı çalıştırıp sonuçları kesiştirmektir:

 comm -12 <(grep -rl word1 . | sort) <(grep -rl word2 . | sort)

1

Git yüklediyseniz

git grep -l --all-match --no-index -e Dansk -e Norsk -e Svenska

--No-index, Git tarafından yönetilmeyen geçerli dizindeki dosyaları arar. Yani bu komut, git deposu olup olmadığına bakılmaksızın herhangi bir dizinde çalışacaktır.


0

Bugün bu sorunu yaşadım ve buradaki tüm tek satırlılar bana başarısız oldu çünkü dosyalar adlarda boşluklar içeriyordu.

Bu işe yarayan bulduğum şey:

grep -ril <WORD1> | sed 's/.*/"&"/' | xargs grep -il <WORD2>
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.