Linux komutu: Yalnızca metin dosyaları nasıl 'bulunur'?


100

Google'da birkaç arama yaptıktan sonra bulduğum şey şu:

find my_folder -type f -exec grep -l "needle text" {} \; -exec file {} \; | grep text

Bu çok kullanışsızdır ve mime türü bilgileri gibi gereksiz metinler çıkarır. Daha iyi bir çözüm var mı? Aynı klasörde, aramam gereken çok sayıda metin dosyası içeren çok sayıda resim ve diğer ikili dosya var.

Yanıtlar:


184

Bunun eski bir iş parçacığı olduğunu biliyorum, ancak bununla karşılaştım ve findyalnızca ikili olmayan dosyaları bulmak için çok hızlı bir yol olduğunu bulduğum yöntemimi paylaşacağımı düşündüm :

find . -type f -exec grep -Iq . {} \; -print

-IGrep seçeneği hemen ikili dosyaları ve görmezden söyler .birlikte seçeneği -qhemen yapmak çok hızlı gider böylece metin dosyaları maç olacak. Değişebilirsin -printa -print0bir içine boru için xargs -0boşluklarla endişe varsa ya da bir şey (lucas.werkmeister @ ipucu için teşekkürler!)

Ayrıca, ilk nokta yalnızca findOS X'teki gibi belirli BSD sürümleri için gereklidir , ancak bunu bir takma ad veya başka bir şeye koymak istiyorsanız, her zaman orada olması hiçbir şeye zarar vermez.

DÜZENLEME : @ruslan'ın doğru bir şekilde işaret ettiği -andgibi, ima edildiği için ihmal edilebilir.


16
Mac OS X'te bunu olarak değiştirmem gerekiyor find . -type f -exec grep -Il "" {} \;.
Alec Jacobson

3
Bu, meslektaşın cevabından daha iyi çünkü 1. soruyu cevaplıyor 2. Yanlış pozitifler vermiyor 3. çok daha performanslı
user123444555621

3
find -type f -exec grep -Iq . {} \; -and -printDosyaları içeride tutma avantajına sahip olanı da kullanabilirsiniz find; sadece metin dosyaları için çalıştırılan bir -printbaşkasıyla değiştirebilirsiniz -exec. ( grepDosya adlarının yazdırılmasına izin verirseniz, dosya adlarını satırsonları ile ayırt edemezsiniz.)
Lucas Werkmeister

1
@ NathanS.Watson-Haigh Olmamalı, çünkü metin dosyalarıyla hemen eşleşmelidir. Paylaşabileceğiniz belirli bir kullanım durumunuz var mı?
crudcore

2
find . -type f -exec grep -Il . {} +çok daha hızlı. Dezavantajı, -exec@ lucas.werkmeister'ın önerdiği gibi başka biri tarafından uzatılamamasıdır
Henning


10

Neden kullanışsız? Sık kullanmanız gerekiyorsa ve her seferinde yazmak istemiyorsanız, bunun için bir bash işlevi tanımlamanız yeterlidir:

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text
}

içine koy .bashrcve sonra çalıştır:

findTextInAsciiFiles your_folder "needle text"

ne zaman istersen.


OP'nin düzenlemesini yansıtmak için DÜZENLE :

mime bilgilerini kesmek istiyorsanız, mime bilgilerini filtreleyen ardışık düzene başka bir aşama ekleyebilirsiniz. Bu neyi önce gelen tek alarak, hile yapmak gerekir :: cut -d':' -f1:

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text | cut -d ':' -f1
}

"Grep metin" in tüm metin dosyalarını tam olarak alacak kadar doğru olup olmadığından emin değilim - yani, mime türü açıklamasının dizesinde 'metin' olmayan herhangi bir metin dosyası türü var mı?
datasn.io

@ kavoir.com: evet. Gönderen filemanuel: "Kullanıcılar dizindeki tüm okunabilir dosyalar kelime 'metin' basılmış olması bilinmesine bağlı."
peoro

2
Metin dosyalarını grep edip sonra filtrelemek yerine greplemeden önce metin dosyalarını aramak biraz daha akıllıca olmaz mıydı?
kullanıcı bilinmiyor

/proc/meminfo, /proc/cpuinfoVb metin dosyalarıdır, ancak file /proc/meminfodiyor /proc/meminfo: empty. 'Metin'e ek olarak' boş'un da test edilmesi gerekip gerekmediğini merak ediyorum, ancak diğer türlerin de 'boş' olduğunu bildirip bildiremeyeceğinden emin değilim.
Timo Kähkönen

"Neden kullanışsız?" - "gereksiz metinler çıkarır". Bu cevap onu pek sevmez.
user123444555621

4
find . -type f -print0 | xargs -0 file | grep -P text | cut -d: -f1 | xargs grep -Pil "search"

Bu maalesef yerden tasarruf sağlamıyor. Bunu bash betiğine koymak, biraz daha kolay hale getirir.

Bu alan güvenli:

#!/bin/bash
#if [ ! "$1" ] ; then
    echo "Usage: $0 <search>";
    exit
fi

find . -type f -print0 \
  | xargs -0 file \
  | grep -P text \
  | cut -d: -f1 \
  | xargs -i% grep -Pil "$1" "%"

2
Komut dosyanızda birkaç sorun vardır: 1. Bir ikili dosya adlandırılırsa ne olur text.bin? 2. Bir dosya adı bir içeriyorsa ne olur :?
thkala

3

Bunu yapmanın başka bir yolu:

# find . |xargs file {} \; |grep "ASCII text"

Siz de boş dosyalar istiyorsanız:

#  find . |xargs file {} \; |egrep "ASCII text|empty"

2

Buna ne dersin:

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable'

Dosya adlarını dosya türleri olmadan istiyorsanız, son bir sedfiltre eklemeniz yeterlidir.

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'

-e 'type'Son grepkomuta daha fazla seçenek ekleyerek gereksiz dosya türlerini filtreleyebilirsiniz .

DÜZENLE:

Senin Eğer xargsversiyonu destekler -dseçeneği, komutlar yukarıda daha basit hale gelir:

$ grep -rl "needle text" my_folder | xargs -d '\n' -r file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'

aptal ben. Özyinelemeli grep fark etmedi. anladığım kadarıyla birçok uygulamada biraz sınırlı olmasına rağmen aslında oldukça hızlı. +1 sizin için.
Antti Rytsölä

2

İşte bunu nasıl yaptım ...

1. bir dosyanın düz metin olup olmadığını test etmek için küçük bir komut dosyası oluşturun:

#!/bin/bash
[[ "$(file -bi $1)" == *"file"* ]]

2. bul daha önce olduğu gibi kullan

find . -type f -exec istext {} \; -exec grep -nHi mystring {} \;

Sanırım demek istiyorsun == *"text"* ]]?
kullanıcı bilinmiyor

Bunun yerine eşleştirme operatörünü "= ~" metin "]]" kullanabilirsiniz.
kullanıcı bilinmiyor

2

Histumluk cevabıyla ilgili iki sorunum var:

  • Yalnızca metin dosyalarını listeler. Aslında istendiği gibi aramıyor. Aslında aramak için kullanın

    find . -type f -exec grep -Iq . {} \; -and -print0 | xargs -0 grep "needle text"
    
  • Her dosya için çok yavaş bir grep süreci oluşturur. O zaman daha iyi bir çözüm

    find . -type f -print0 | xargs -0 grep -IZl . | xargs -0 grep "needle text"
    

    ya da sadece

    find . -type f -print0 | xargs -0 grep -I "needle text"
    

    Bu, yukarıdaki çözüm için 4 saniyeye kıyasla yalnızca 0,2 saniye sürer (2,5 GB veri / 7700 dosya), yani 20 kat daha hızlı .

Ayrıca kimse ag, Silver Searcher veya ack- grep'i alternatif olarak göstermedi. Bunlardan biri varsa, çok daha iyi alternatiflerdir:

ag -t "needle text"    # Much faster than ack
ack -t "needle text"   # or ack-grep

Son bir not olarak, yanlış pozitiflere dikkat edin (metin dosyaları olarak alınan ikili dosyalar). Grep / ag / ack kullanarak zaten yanlış pozitif aldım, bu yüzden dosyaları düzenlemeden önce eşleşen dosyaları daha iyi listeleyin.


1

Eski bir soru olmasına rağmen, bu bilginin buradaki cevapların kalitesini artıracağını düşünüyorum.

Yürütülebilir bit kümesine sahip dosyaları yok sayarken , sadece şu komutu kullanıyorum:

find . ! -perm -111

Diğer dizinlere tekrar tekrar girmesini önlemek için:

find . -maxdepth 1 ! -perm -111

Çok sayıda komutu karıştırmak için borulara gerek yok , sadece güçlü düz bulma komutu.

  • Sorumluluk reddi: OP'nin tam olarak istediği şey bu değil, çünkü dosyanın ikili olup olmadığını kontrol etmiyor. Örneğin, kendileri metin olan ancak çalıştırılabilir bit setine sahip olan bash betik dosyalarını filtreleyecektir .

Bununla birlikte, umarım bu herkes için yararlıdır.


0

Bunu şu şekilde yapıyorum: 1) arama yapmak için çok fazla dosya (~ 30k) olduğundan, aşağıdaki komutu kullanarak crontab aracılığıyla günlük olarak metin dosyası listesi oluşturuyorum:

find /to/src/folder -type f -exec file {} \; | grep text | cut -d: -f1 > ~/.src_list &

2) .bashrc'de bir işlev oluşturun:

findex() {
    cat ~/.src_list | xargs grep "$*" 2>/dev/null
}

Sonra aramayı yapmak için aşağıdaki komutu kullanabilirim:

findex "needle text"

HTH :)


0

Xargs'ı tercih ederim

find . -type f | xargs grep -I "needle text"

dosya adlarınız tuhafsa -0 seçeneklerini kullanarak arayın:

find . -type f -print0 | xargs -0 grep -I "needle text"

0
  • Tüm metin / ascii dosyalarında / etc içindeki "eth0" metnini taramak için bash örneği

grep eth0 $ (bul / etc / -type f -exec dosyası {} \; | egrep -i "metin | ascii" | kes -d ':' -f1)


0

Bir satıra birden fazla komutun nasıl yerleştirileceğini öğrenmeye çalışan benim gibi yeni başlayanlar için genişletilmiş açıklamalı basitleştirilmiş bir versiyon.

Sorunu adım adım yazacak olsaydın, şöyle görünürdü:

// For every file in this directory
// Check the filetype
// If it's an ASCII file, then print out the filename

Bunu başarmak için, biz üç UNIX komutları kullanabilirsiniz: find, file, ve grep.

find dizindeki her dosyayı kontrol edecek.

filebize dosya türünü verecek. Bizim durumumuzda, 'ASCII metni' dönüşü arıyoruz

grep çıkışta 'ASCII' anahtar kelimesini arayacaktır. file

Peki bunları tek bir satırda nasıl dizebiliriz? Bunu yapmanın birden fazla yolu var, ancak bunu sahte kodumuza göre yapmanın en mantıklı olduğunu görüyorum (özellikle benim gibi yeni başlayanlar için).

find ./ -exec file {} ";" | grep 'ASCII'

Karmaşık görünüyor, ancak çözdüğümüzde fena değil:

find ./= bu dizindeki her dosyaya bak. find'İfadesini' kibrit veya ne olursa olsun herhangi bir dosyanın dosya adı dışarı komut baskılar bizim durumumuzda geçerli dizin veya yolu, sonra gelir./

Anlaşılması gereken en önemli şey, ilk bitten sonraki her şeyin Doğru veya Yanlış olarak değerlendirileceğidir. True ise, dosya adı yazdırılacaktır. Değilse, komut devam eder.

-exec= bu bayrak, arama ifadesi olarak başka bir komutun sonucunu kullanmamıza izin veren, bul komutu içindeki bir seçenektir. Bu, bir işlev içindeki bir işlevi çağırmak gibidir.

file {}= içinde çağrılan komut find. fileKomut size bir dosyanın filetype anlatan bir dize döndürür. Düzenli, bu gibi görünecektir: file mytextfile.txt. Bizim durumumuzda, findkomut tarafından bakılan dosyayı kullanmasını istiyoruz , bu yüzden {}boş bir değişken veya parametre olarak davranması için küme parantezleri koyuyoruz . Başka bir deyişle, sistemden dizindeki her dosya için bir dize çıkarmasını istiyoruz.

";"= bu gerekli findve -execkomutumuzun sonundaki noktalama işaretidir . Çalıştırarak ihtiyacınız varsa daha fazla açıklama için 'bul' kılavuzuna bakın man find.

| grep 'ASCII'= |bir borudur. Boru solda olanın çıktısını alır ve sağdakine girdi olarak kullanır. findKomutun (tek bir dosyanın dosya türü olan bir dize) çıktısını alır ve dizeyi içerip içermediğini test eder 'ASCII'. Varsa, true döner.

ŞİMDİ, sağındaki ifade find ./, grepkomut true döndürdüğünde true döndürür. Voila.


0

fileGücü ile birleştirilmiş harika yardımcı programı kullanarak herhangi bir dosya türünü sihirli baytlarına göre bulmakla ilgileniyorsanız find, bu kullanışlı olabilir:

$ # Let's make some test files
$ mkdir ASCII-finder
$ cd ASCII-finder
$ dd if=/dev/urandom of=binary.file bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.009023 s, 116 MB/s
$ file binary.file
binary.file: data
$ echo 123 > text.txt
$ # Let the magic begin
$ find -type f -print0 | \
    xargs -0 -I @@ bash -c 'file "$@" | grep ASCII &>/dev/null && echo "file is ASCII: $@"' -- @@

Çıktı:

file is ASCII: ./text.txt

Açıklama: $Komutlarımızı girdiğimiz etkileşimli kabuk istemidir

Daha sonra &&başka bir komut dosyasını çağırmak veya başka şeyler de satır içinde yapmak için parçayı değiştirebilirsiniz , yani bu dosya belirli bir dizeyi içeriyorsa, tüm dosyayı cat veya içinde ikincil bir dizgi arayın.

Açıklama:

  • find dosya olan öğeler
  • Yap xargsbir liner içine bir çizgi olarak her öğeyi beslemek bash komut / script
  • filedosya türünü sihirli bayta göre grepkontrol eder, ASCII'nin var olup olmadığını kontrol eder, eğer öyleyse, &&sonraki komutunuz çalıştırıldıktan sonra .
  • findsonuçları nullayrı yazdırır ; bu, dosya adlarından boşluk ve meta karakterlerle kaçmak için iyidir.
  • xargs-0seçeneği kullanarak , bunları nullayrı okur , -I @@ her kaydı alır ve bash betiğine konumsal parametre / argüman olarak kullanır.
  • --için bashbir argüman sonra gelirse teminat altın onunla başlasa bile -gibi -caksi bash seçenek olarak yorumlanabilecek olan

ASCII dışında türler bulmanız gerekirse, başka türlerle değiştirin grep ASCII, örneğingrep "PDF document, version 1.4"


-1
find . -type f | xargs file | grep "ASCII text" | awk -F: '{print $1}'

Tüm dosyaları listelemek için find komutunu kullanın, metin olduklarını doğrulamak için dosya komutunu kullanın (tar, anahtar değil), son olarak sonucu filtrelemek ve yazdırmak için awk komutunu kullanın.


-4

Buna ne dersin

 find . -type f|xargs grep "needle text"

Bu "needle text"
aranmıyor

@Navi: sağlanan örnek OP yalnızca şunu içeren dosyaları bulur"needl text"
peoro

3
@Navi: artık metin dosyalarını aramıyor: eğer bir ikili dosya içeriyorsa "needle text"bulunur
peoro

Neden seni dinliyorum ki?
Navi

1
@Navi: tek satırlık programınız dosya türlerini kontrol etmiyor ve dosya adlarında boşluklarla ilgili büyük sorunlar
yaşı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.