Çok sayıda dosyada dizenin son oluşumunu bulma


9

Bir dize son kez bulmak için birden çok günlük dosyaları (son 24 saat içinde oluşturulan tüm dosyaları, aynı dizinde tutulan) aramak gerekir. Bu yazdığım komut:

find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1

Ancak bu, bir dosya için yalnızca son satırı döndürür. Tüm satırları almak için bu nasıl tweak hakkında herhangi bir öneriniz var mı?


kuyruğu ve son grep'i tersine çevirmeye çalıştın mı? bulmak. -zaman 1 | grep dosya ön düzeltmesi | xargs kuyruk -1 | grep 'arama dizesi'
Mathieu

Yanıtlar:


4

GNU tesislerini varsayarsak:

find . -mtime -1 -exec bash -c \
'for f; do tac "$f" | grep -m1 fileprefix; done' _ {} +

Zaten bash kabuğunu kullandığım için lütfen 'bash -c \' amacını ayrıntılı olarak açıklayabilir misiniz? Ayrıca sonunda '_ {} +' nın amacı.
Lokesh

@Lokesh, findkullanarak dosyalar üzerinde komutları çalıştırabilirsiniz -exec. İle bash -c, her biri bashtarafından bulunan findve tac .. | grep -m1 fileprefixher biri üzerinde çalışan dosyaları dolaşan bir kabuk ortaya
çıkarıyoruz

Ben kesim komutu yani f için dahil ederek döngü için dize filtreleme genişletmeye çalışıyordu; tac "$ f" yap | grep -m1 dosya ön düzeltmesi | cut -d '' -f4,7-8 ama cut komutunu verdiğim an bana beklenmeyen dosya sonu hatası veriyor. Ne yaptığımı önerebilir misiniz lütfen.
Lokesh

@lokesh, -d" "kesim ile kullanın . Tek yerine çift tırnak
iruvar

1
findKomut dosyası öneki için filtreleyebilirsiniz; grepBunun için gerekli olmamalıdır. Arama dizesinin bu cevapta yer almaması da şaşırtıcıdır.
Jonathan Leffler

8

Her şey tek bir dizindeyse şunları yapabilirsiniz:

for file in *fileprefix*; do
    grep 'search string' "$file" | tail -1
done

Bunlar büyük dosyalarsa, tacdosyayı ters sırada (önce son satır) yazdırmak ve ardından grep -m1ilk tekrarla eşleştirmek için işleri hızlandırmaya değer olabilir . Bu şekilde, tüm dosyayı okumak zorunda kalmazsınız:

for file in *fileprefix*; do
    tac file | grep -m1 'search string'
done

Her ikisi de eşleşen dizin olmadığını varsayar fileprefix. Varsa, göz ardı edebileceğiniz bir hata alırsınız. Bu bir sorunsa, yalnızca dosyaları kontrol edin:

 for file in *fileprefix*; do
    [ -f "$file" ] && tac file | grep -m1 'search string'
 done

Basılacak dosya adına da ihtiyacınız varsa, -Hher grepçağrıyı ekleyin . Veya, grepdesteklemiyorsa, arama yapmasını da söyleyin /dev/null. Bu, çıktıyı değiştirmez, ancak grepbirden fazla dosya verildiğinden, her isabet için her zaman dosya adını yazdırır:

for file in *fileprefix*; do
    grep 'search string' "$file" /dev/null | tail -1
done

“Bu şekilde, tüm dosyayı okumak zorunda kalmazsınız” - uh? Hayır, tüm dosyayı grep'te okumaktan kaçınırsınız, bunun yerine tüm dosyayı tac aracılığıyla koyarsınız. Maçın dosyanın başlangıcına veya sonuna yaklaşmasına bağlı olmasına rağmen, bunun daha hızlı olacağı açık değil.
Gilles 'SO- kötü olmayı bırak'

@Gilles hayır, tüm dosyayı tacda aktarmazsınız . İlk maç bulunur bulunmaz çıkış yapılacaktır. Sadece 832M metin dosyası ve son satırda bulunan bir desenle test ettim. grep -m 1 pattern filearacı ~ 7 saniye ve tac file | grep -m1 patternaldı 0.009.
terdon

4
find . ! -name . -prune -mtime 1 -name 'fileprefix*' \
     -exec sed -se'/searchstring/h;$!d;x' {} +

... ayrı dosyalar seçeneğini ve bir POSIX'i seddestekleyen -sGNU'nuz varsa çalışır find.

Ancak, ! -type dveya -type fniteleyicileri eklemelisiniz , çünkü bir dizini okumaya çalışmak çok faydalı olmayacaktır ve aralığı normal dosyalara daha da daraltmak, bir kanalda veya seri aygıt dosyasında okunmayı engelleyebilir.

Mantık inanılmaz derecede basittir - eski alanını, eşleşen herhangi bir giriş satırının bir kopyasıyla sedüzerine yazar , ardından tüm giriş satırlarından çıktıyı alır, ancak her giriş dosyası için sonuncudan çıkarır. Son satıra geldiğinde , tutma ve desen boşluklarını değiştirir ve böylece dosyayı okurken bulunursa, bu tür son olay çıktıya otomatik olarak yazdırılır, aksi takdirde boş bir satır yazar. ( istenmediyse komut dosyasının kuyruğuna ekleyin ) .hsearchstringdxsearchstring/./!dsed

Bu işlem sed65k giriş dosyası başına veya ARG_MAXsınırınız ne olursa olsun tek bir çağrı yapar . Bu çok performanslı bir çözüm olmalı ve oldukça basit bir şekilde uygulanmalıdır.

Dosya adlarını da istiyorsanız, yeni bir GNU verildiğinde, sedbunları Fkomutla ayrı satırlara yazabilir veya başka findbir adın başına -printbirincil ekleyerek bunları toplu iş başına ayrı bir listede yazdırabilirsiniz +.


1

Nasıl olur:

find . -mtime -1 -name "fileprefix*" -exec sh -c \
'echo "$(grep 'search string' $1 | tail -n 1),$1"' _ {} \;

Yukarıda, her dosyada bir arama dizesinin son tekrarını ve ardından virgülden sonra ilgili dosya adını içeren güzel bir çıktı verir (biçimlendirmeyi değiştirmek veya gereksizse kaldırmak için yankı altındaki ", $ 1" bölümünü değiştirin). "Dosya" ad önekine sahip dosyalarda '10' arama dizesini arayan örnek çıktı aşağıdaki gibidir:

[dmitry@localhost sourceDir]$ find . -mtime -1 -name "file*" -exec  sh -c 'echo "$(grep '10' $1 | tail -n 1),$1"' _ {} \;
Another data 02 10,./file02.log
Some data 01 10,./file01.log
Yet another data 03 10,./file03.log 

1
find . -mtime 1 -name 'fileprefix*' -exec grep -Hn 'search string' {} + |
    sort -t: -k1,2 -n | 
    awk -F: '{key=$1 ; $1="" ; $2="" ; gsub(/^  /,"",$0); a[key]=$0} 
             END {for (key in a) { print key ":" a[key] }}'

Bu GNU kullandığı grep'ın -Hve -nher zaman dosya adını ve tüm maçları LINENUMBER hem yazdırmak için seçenekler, o zaman dosya adı ve LineNumber ve awk içine borular bunu, tarafından sıralar depolayan, dizideki her dosya için son maç ve sonunda baskılar o.

Oldukça kaba bir yöntem ama işe yarıyor.

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.