Find kullanarak bulunan dosyaların içeriğini nasıl tek bir dosyada toplayabilirim?


11

Değerli verileri tutan bir bölümü yeniden biçimlendirerek kendimi acı çektiği yere (gerçekten kötü) vurmayı başardım. Tabii ki kasıtlı değildi, ama oldu.

Ancak, verilerin çoğunu kullanmayı testdiskve photoreckurtarmayı başardım . Şimdi tüm bu veriler neredeyse 25.000 dizin üzerinde dağıtıldı. Dosyaların çoğu .txt dosyası, geri kalanı ise görüntü dosyalarıdır. Her dizinde 300'den fazla .txt dosyası vardır.

Ben grepveya find.txt dosyalarından belirli dizeleri ayıklamak ve bunları bir dosyaya çıktı için kullanabilirsiniz. Örneğin, verilerimin kurtarılan dosyalarda olduğunu doğrulamak için kullandığım bir satır:

find ./recup*/ -name '*.txt' -print | xargs grep -i "searchPattern"

Bir dosyaya "searchPattern" çıktısını verebilirim, ama bu sadece bana bu kalıbı verir. İşte gerçekten başarmak istiyorum:

Tüm dosyaları gözden geçirin ve belirli bir dizeyi arayın. Bu dize bir dosyada bulunursa, TÜM dosyanın içeriğini bir çıktı dosyasına aktarın. Desen birden fazla dosyada bulunursa, sonraki dosyaların içeriğini bu çıktı dosyasına ekleyin. Sadece aradığım kalıbı çıkarmak istemiyorum, ancak kalıpların bulunduğu dosyanın TÜM içeriğini.

Bu yapılabilir olduğunu düşünüyorum, ama sadece belirli bir desen ondan sonra bir dosyanın tüm içeriğini kapmak için nasıl bilmiyorum.


Sağladığınız komutla, aradığınız sonuçları verir, ancak çıktıyı bir metin dosyasına yönlendirmek mi istiyorsunuz?
ryekayo

Sorumu okuduktan sonra, "Geç ..." ile başlayan paragraf aynı psuedocode gibi geliyor. Belki ben / eğer Python kodu için birkaç satır kodu alabilirsiniz. Daha bilinçli bir cevap beklerken
Ami

Kesinlikle psuedocode, ve eminim bash da yapmak için bir yol bulabilirsiniz.
ryekayo

@ryekayo, Evet, bu bana çıktı veriyor, ama bu sadece belirli bir veri türünün hangi dosyada olduğunu bulmak için, bu verilerin daha fazla o dosyada olduğunu söyler. Bu yüzden o dosyadaki her şeyi alıp başka bir dosyaya yazmak istiyorum.
Ami

Muhtemelen bir tür bu komutu sarın eğer içindekiler dışarı kutu kedi eğer deyim durumunda veya sonuçlarına dayalı olduğu bir işlevi çağırabilir deyim hatta bir switch-case
ryekayo

Yanıtlar:


10

Hedefinizi doğru anlarsam, aşağıdakiler istediğinizi yapar:

find ./recup*/ -name '*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

Bu, *.txtiçindeki tüm dosyaları arayacak ./recup*/, her birini test edecek searchPattern, eğer eşleşirse catdosya olacaktır. Tüm cated dosyalarının çıktıları yönlendirilecektir outputfile.txt.

Her desen ve çıktı dosyası için tekrarlayın.


Eşleşen çok sayıda dizininiz ./recup*varsa, sonunda bir argument list too long error. Bunun basit yolu, bunun gibi bir şey yapmaktır:

find ./ -mindepth 2 -path './recup*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

Bu, tam yolla eşleşecektir. Böylece ./recup01234/foo/bar.txteşleşecek. -mindepth 2O Eşleşmeyecek öyle mi ./recup.txtya ./recup0.txt.


Evet, sanırım bunu yapacak. Ve bu bana çalışmam için bir temel sağlıyor. Birden fazla dizeyi arayacağım için, birden fazla elif ile bir kod / for bit kodu, görevi otomatikleştirmeme yardımcı olacağını düşünüyorum. Teşekkür ederim
Ami

Thats bile düşündüğümden daha iyi lol
ryekayo

Bu işe yaramadı. Şu hatayı aldım: "/ usr / bin / find çalıştırılamadı: Bağımsız değişken listesi çok uzun"
Ami

@ Bu konuya bir çözüm sağlamak için cevabı güncelledi.
Patrick

2
Birden dizeleri kullanıyorsanız @Ami, sadece başka bir dosyaya (bütün olumlu dosya adlarını kaydetmek için basit olabilir grep -l, daha sonra) |sort|uniqve catdosya listesinden.
Sparhawk

3

Deseninizi çıktılamak yerine, grep üzerinde "-l" kullanarak dosya adını çıktı alın ve sonra cat'a girdi olarak kullanın.

find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern" | xargs cat

veya

cat $( find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern")

Kalan bilgileri doldurabileceğinizden şüpheleniyorum. BTW, dosya adlarında boşluklar veya başka garip karakterler varsa (bu özel durumda olması muhtemel değildir, ancak gelecekteki amaçlar için), bulmada -print0 ve grep'te -Z seçeneğini kullanın ve kullanılacak xargs üzerinde -0 seçeneğiyle birlikte kullanın yeni satırlar yerine dosya adları arasında boş bayt sayısı.

find ./recup*/ -name '*.txt' -print0 | xargs -0 grep -Zli "searchPattern" | xargs -0 cat

2
Ayrıca her dosya için yeni bir çatala (iyi, klon ()) ve exec'ye neden olması dışında Patrick'in "iki-exec" seçeneğini de seviyorum. Normalde kullanabilirsiniz \+ziyade \;bu sorunu önlemek için, ama -exec args bir çift o eserler (I "kötü" şüpheli) bilmiyorum. Bir çift xargs kullanarak, sadece birkaç dosya ile daha hızlı olması gereken birkaç yeni işleme sahip olursunuz.
dannysauer

Bu da iyi görünüyor. Teşekkürler. Bir noob sorusu: Son xargs'tan sonraki kedi bir dosyaya çıktı almalı, değil mi?
Ami

İlk okuduğumda, dosyanın içeriğinin nereye gitmesi gerektiğini belirten soruyu düşünmedim. Bu komutların üçü de dosya içeriğini STDOUT'a koyar, böylece sadece (sonuna kadar) >afileveya |acommanddurumunuza uygun olanı eklersiniz. :)
dannysauer

İyi cevap, pg_hba.conf kedi gerekiyordusudo find /* -name pg_hba.conf | xargs sudo cat
App Work

Bu biraz konu dışı, ama sudo xargsyerine kullanmayı tercih ediyorum xargs sudo. Çalıştırdığınızda xargs sudo, komut olduğunu varsayarak komut satırını oluşturur sudo cat args. Ama kedi / bin içinde, o zaman sudo çalışır /bin/cat args. Komutunuz / usr / local / bin gibi daha uzun bir dizindeyse, sudo aslında çalıştırılan komut çok uzun bir komut satırına ve izlenmesi zor bir hataya neden olabilir. Bunun üzerine, sudo xargsxargs xargs sudokomutunu çalıştırdığınız günlükleri kaydederken, komutu tüm bağımsız değişkenlerle günlüğe kaydeder ve bazı uzun sudo günlük satırlarına neden olur. :)
dannysauer

1

Bu tam olarak en uygun kod değildir, ancak çok basittir ve verimlilik bir sorun değilse iyi çalışır. Sorun, dize zaten bulunmuş olsa bile, dosyalar arasında birden çok kez kaybolmasıdır.

İlk olarak, dizelerinizi arayın ve eşleşen dosyaları bir listeye yazın.

find ./recup*/ -name '*.txt' -execdir grep -il "searchPattern" {} >> /tmp/file_list \;

searchPatternGerekirse bu adımı tekrarlayın . Bu, adresindeki eşleşen dosyaların bir listesini oluşturur /tmp/file_list.

Sorun, bu dosyanın içinde kopyalar olması olabilir. Bu nedenle, kopyaları ile değiştirebiliriz |sort|uniq. sortBöylece parça, birbirine bitişik çiftleri yerleştirir uniqbunları kaldırabilir. Daha sonra catbu dosyaları xargs(her dosya adı yeni satırla ayrılmış olarak \n) kullanarak birlikte yapabilirsiniz . Bu nedenle,

</tmp/file_list sort | uniq | xargs -d "\n" cat > final_file.txt

Diğer cevapların aksine, bunun içinde iki adım ve geçici bir dosya var, bu yüzden gerçekten sadece bulmak için birden fazla deseniniz varsa tavsiye ederim.


0

Kabuğunuza ve ortamınıza bağlı olarak, böyle bir şey yapabilirsiniz (bashta)

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1\|searchPattern2\|searchPattern3' "$file"; then
    cat "$file" >> some/other/file
  fi
done < <(find ./recup*/ -name '*.txt' -print0)

Sonuçları desene göre ayırmak istiyorsanız, bunu aşağıdaki gibi değiştirebilirsiniz:

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1' "$file"; then
    cat "$file" >> some/other/file1
  elif grep -qim1 'searchPattern2' "$file"; then
    cat "$file" >> some/other/file2
  elif grep -qim1 'searchPattern3' "$file"; then
    cat "$file" >> some/other/file3
  fi
done < <(find ./recup*/ -name '*.txt' -print0)

"Tamamlandıktan" sonra ne yapar? Aslında ben gibi olacak eğer blok eşleşen bir desen içeren dosyaları farklı yazılır böylece blok değiştirmek olduğunu.
Ami

Yalnızca bulunan '.txt' dosyalarını listeler, her biri boş karakterle sonlandırılır (böylece boşluklar ve diğer karakterler içeren dosya adları için güvenlidir). whileDöngü sonra bu listeleri okur ve does grep/ koşullu catbölümünü.
steeldriver

Kodu çalıştırmayı denediğimde şu hatayı alıyorum: ./recoverData.sh: Sözdizimi hatası: "(" beklenmedik. Bu, find komutunun etrafındaki parantezlerden geliyor
Ami

Hangi kabuğu kullanıyorsun? süreç ikame sözdizimi
bash'a özgüdür

1
Komut (lar) ı doğrudan etkileşimli bir bash kabuğunda yürütebilir ya da ilk satırı shebang içeren bir dosyaya koyabilir #!/bin/bash, çalıştırılabilir hale getirebilir chmod +x recoverData.shve kullanarak yürütebilirsiniz ./recoverData.sh. Do not kullanmak sh recoverData.shberi /bin/sholasılıkla bir olduğunu dashkabuk .
steeldriver
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.