Perintah Linux: Bagaimana cara 'menemukan' hanya file teks?

100

Setelah beberapa pencarian dari Google, yang saya dapatkan adalah:

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

yang sangat tidak berguna dan mengeluarkan teks yang tidak diperlukan seperti informasi jenis mime. Ada solusi yang lebih baik? Saya memiliki banyak gambar dan file biner lainnya di folder yang sama dengan banyak file teks yang perlu saya cari.

datasetn.io
sumber

Jawaban:

184

Saya tahu ini adalah utas lama, tetapi saya menemukannya dan berpikir saya akan membagikan metode saya yang menurut saya merupakan cara yang sangat cepat untuk digunakan finduntuk hanya menemukan file non-biner:

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

The -Ipilihan untuk grep mengatakan itu untuk segera mengabaikan file biner dan .pilihan bersama dengan -qakan membuatnya segera mencocokkan file teks sehingga berjalan sangat cepat. Anda dapat mengubah -printmenjadi -print0untuk perpipaan menjadi an xargs -0atau sesuatu jika Anda khawatir tentang spasi (terima kasih atas tipnya, @ lucas.werkmeister!)

Juga titik pertama hanya diperlukan untuk versi BSD tertentu findseperti di OS X, tetapi tidak ada salahnya hanya menyimpannya di sana setiap saat jika Anda ingin memasukkannya ke dalam alias atau sesuatu.

EDIT : Seperti yang ditunjukkan @ruslan dengan benar, -anddapat dihilangkan karena sudah tersirat.

crudcore
sumber
16
Di Mac OS X, saya perlu mengubahnya menjadi find . -type f -exec grep -Il "" {} \;.
Alec Jacobson
3
Ini lebih baik daripada jawaban peoro karena 1. itu benar-benar menjawab pertanyaan 2. Tidak menghasilkan positif palsu 3. itu jauh lebih berkinerja
user123444555621
3
Anda juga dapat menggunakan find -type f -exec grep -Iq . {} \; -and -printyang memiliki keuntungan karena menyimpan file find; Anda dapat menggantinya -printdengan yang lain -execyang hanya dijalankan untuk file teks. (Jika Anda membiarkan grepmencetak nama file, Anda tidak akan dapat membedakan nama file dengan baris baru di dalamnya.)
Lucas Werkmeister
1
@ NathanS.Watson-Haigh Seharusnya tidak, karena harus segera mencocokkan file teks. Apakah Anda memiliki kasus penggunaan khusus yang dapat Anda bagikan?
crudcore
2
find . -type f -exec grep -Il . {} +jauh lebih cepat. Kekurangannya adalah tidak dapat diperpanjang oleh yang lain -execseperti yang disarankan @ lucas.werkmeister
Henning
11

Berdasarkan pertanyaan SO ini :

grep -rIl "needle text" my_folder

crayzeewulf
sumber
Terima kasih, -Iini adalah penyelamat.
Dominique
10

Mengapa tidak berguna? Jika Anda perlu sering menggunakannya, dan tidak ingin mengetiknya setiap kali cukup tentukan fungsi bash untuknya:

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

taruh di Anda .bashrcdan kemudian jalankan saja:

findTextInAsciiFiles your_folder "needle text"

kapanpun kamu mau.


EDIT untuk mencerminkan edit OP:

jika Anda ingin memotong informasi pantomim, Anda bisa menambahkan tahap lebih lanjut ke saluran pipa yang menyaring informasi pantomim. Ini harus melakukan trik, dengan mengambil hanya apa yang datang sebelum :: 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
}
peoro
sumber
Saya tidak yakin apakah "teks grep" cukup akurat untuk mendapatkan semua file teks - maksud saya, apakah ada jenis file teks yang tidak memiliki 'teks' dalam string deskripsi jenis mime?
datasetn.io
@ kavoir.com: ya. Dari filemanual: "Pengguna bergantung pada mengetahui bahwa semua file yang dapat dibaca di direktori memiliki kata 'teks' yang dicetak."
peoro
2
Bukankah akan lebih pintar mencari file teks sebelum grep, daripada grep dan kemudian memfilter file teks?
pengguna tidak diketahui
/proc/meminfo, /proc/cpuinfodll. adalah file teks, tetapi file /proc/meminfobertuliskan /proc/meminfo: empty. Saya bertanya-tanya apakah 'kosong' harus diuji selain 'teks', tetapi tidak yakin apakah juga jenis lain bisa melaporkan 'kosong'.
Timo Kähkönen
"Mengapa tidak berguna?" - "mengeluarkan teks yang tidak dibutuhkan". Jawaban ini tidak meyakinkan.
pengguna123444555621
4
find . -type f -print0 | xargs -0 file | grep -P text | cut -d: -f1 | xargs grep -Pil "search"

Sayangnya ini tidak menghemat ruang. Menempatkan ini ke dalam skrip bash membuatnya sedikit lebih mudah.

Ini adalah ruang aman:

#!/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" "%"
Antti Rytsölä
sumber
2
Ada beberapa masalah dalam skrip Anda: 1. bagaimana jika file biner diberi nama text.bin? 2. Bagaimana jika nama file mengandung :?
thkala
3

Cara lain untuk melakukan ini:

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

Jika Anda ingin file kosong juga:

#  find . |xargs file {} \; |egrep "ASCII text|empty"
The IT Guy
sumber
2

Bagaimana dengan ini:

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

Jika Anda menginginkan nama file tanpa jenis file, cukup tambahkan sedfilter terakhir .

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

Anda dapat memfilter jenis file yang tidak dibutuhkan dengan menambahkan lebih banyak -e 'type'opsi ke grepperintah terakhir .

EDIT:

Jika xargsversi Anda mendukung -dopsi tersebut, perintah di atas menjadi lebih sederhana:

$ grep -rl "needle text" my_folder | xargs -d '\n' -r file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'
thkala
sumber
saya konyol. Tidak memperhatikan grep rekursif. seperti yang saya pahami sebenarnya cukup cepat meskipun agak terbatas di banyak aplikasi. 1 untuk Anda.
Antti Rytsölä
2

Inilah cara saya melakukannya ...

1. buat skrip kecil untuk menguji apakah sebuah file berupa teks biasa dalam teks:

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

2. gunakan temukan seperti sebelumnya

find . -type f -exec istext {} \; -exec grep -nHi mystring {} \;
Robert
sumber
Saya kira maksud Anda == *"text"* ]]?
pengguna tidak diketahui
Anda dapat menggunakan operator pencocokan `= ~" text "]]`.
pengguna tidak diketahui
2

Saya memiliki dua masalah dengan jawaban histumness:

  • Ini hanya mencantumkan file teks. Itu tidak benar-benar mencari mereka seperti yang diminta. Untuk benar-benar menelusuri, gunakan

    find . -type f -exec grep -Iq . {} \; -and -print0 | xargs -0 grep "needle text"
    
  • Ini memunculkan proses grep untuk setiap file, yang sangat lambat. Maka solusi yang lebih baik

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

    atau sederhananya

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

    Ini hanya membutuhkan 0,2 detik dibandingkan 4 detik untuk solusi di atas (2.5GB data / 7700 file), yaitu 20x lebih cepat .

Juga, tidak ada yang mengutip ag, Silver Searcher atau ack-grep sebagai alternatif. Jika salah satu dari ini tersedia, mereka adalah alternatif yang jauh lebih baik:

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

Sebagai catatan terakhir, waspadalah terhadap positif palsu (file biner diambil sebagai file teks). Saya sudah memiliki positif palsu menggunakan grep / ag / ack, jadi lebih baik daftarkan file yang cocok terlebih dahulu sebelum mengedit file.

fuujuhi
sumber
1

Meskipun ini adalah pertanyaan lama, saya rasa info di bawah ini akan menambah kualitas jawaban di sini.

Saat mengabaikan file dengan bit set yang dapat dieksekusi , saya hanya menggunakan perintah ini:

find . ! -perm -111

Untuk mencegahnya masuk ke direktori lain secara rekursif:

find . -maxdepth 1 ! -perm -111

Tidak perlu pipa untuk mencampur banyak perintah, cukup perintah pencarian biasa yang kuat .

  • Penafian: tidak persis seperti yang diminta OP, karena tidak memeriksa apakah file tersebut biner atau bukan. Ini akan, misalnya, memfilter file skrip bash , yang merupakan teks itu sendiri tetapi memiliki bit yang dapat dieksekusi .

Karena itu, saya harap ini bermanfaat bagi siapa saja.

Dr Beco
sumber
0

Saya melakukannya dengan cara ini: 1) karena ada terlalu banyak file (~ 30k) untuk dicari, saya membuat daftar file teks setiap hari untuk digunakan melalui crontab menggunakan perintah di bawah ini:

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

2) buat fungsi di .bashrc:

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

Kemudian saya dapat menggunakan perintah di bawah ini untuk melakukan pencarian:

findex "needle text"

HTH :)

Frank Fang
sumber
0

Saya lebih suka xargs

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

jika nama file Anda aneh cari menggunakan opsi -0:

find . -type f -print0 | xargs -0 grep -I "needle text"
dalore
sumber
0
  • Contoh bash untuk menelusuri teks "eth0" di / etc di semua file teks / ascii

grep eth0 $ (temukan / etc / -type f -exec file {} \; | egrep -i "text | ascii" | cut -d ':' -f1)

Gabriel G
sumber
0

Berikut adalah versi yang disederhanakan dengan penjelasan tambahan untuk pemula seperti saya yang mencoba mempelajari cara meletakkan lebih dari satu perintah dalam satu baris.

Jika Anda menuliskan masalah dalam langkah-langkah, akan terlihat seperti ini:

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

Untuk mencapai hal ini, kita dapat menggunakan tiga UNIX perintah: find, file, dan grep.

find akan memeriksa setiap file di direktori.

fileakan memberi kami jenis file. Dalam kasus kami, kami mencari pengembalian 'teks ASCII'

grep akan mencari kata kunci 'ASCII' pada keluaran dari file

Jadi bagaimana kita bisa merangkai ini menjadi satu baris? Ada banyak cara untuk melakukannya, tetapi menurut saya melakukannya dalam urutan kode semu adalah yang paling masuk akal (terutama bagi pemula seperti saya).

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

Terlihat rumit, tapi lumayan saat kita memecahnya:

find ./= lihat semua file di direktori ini. The findperintah print nama file dari file yang cocok dengan 'ekspresi', atau apa pun yang datang setelah jalan, yang dalam hal ini adalah direktori saat ini atau./

Hal terpenting untuk dipahami adalah bahwa segala sesuatu setelah bit pertama itu akan dievaluasi sebagai Benar atau Salah. Jika Benar, nama file akan dicetak. Jika tidak, maka perintah akan terus berlanjut.

-exec= Bendera ini adalah opsi di dalam perintah find yang memungkinkan kita menggunakan hasil dari beberapa perintah lain sebagai ekspresi pencarian. Ini seperti memanggil suatu fungsi dalam suatu fungsi.

file {}= perintah dipanggil di dalam find. The fileperintah mengembalikan sebuah string yang memberitahu Anda filetype file. Secara teratur, itu akan terlihat seperti ini: file mytextfile.txt. Dalam kasus kami, kami ingin itu menggunakan file apa pun yang sedang dilihat oleh findperintah, jadi kami memasukkan tanda kurung kurawal {}untuk bertindak sebagai variabel kosong, atau parameter. Dengan kata lain, kami hanya meminta sistem untuk mengeluarkan string untuk setiap file di direktori.

";"= ini diperlukan oleh finddan merupakan tanda baca di akhir -execperintah kita . Lihat manual untuk 'temukan' untuk penjelasan lebih lanjut jika Anda membutuhkannya dengan menjalankan man find.

| grep 'ASCII'= |adalah pipa. Pipa mengambil keluaran dari apapun yang ada di kiri dan menggunakannya sebagai masukan untuk apapun yang ada di sebelah kanan. Ini mengambil output dari findperintah (string yang merupakan jenis file dari satu file) dan mengujinya untuk melihat apakah itu berisi string 'ASCII'. Jika ya, hasilnya benar.

SEKARANG, ekspresi di sebelah kanan find ./akan mengembalikan nilai benar saat grepperintah mengembalikan nilai benar. Voila.

mepler
sumber
0

Jika Anda tertarik untuk menemukan jenis file apa pun berdasarkan byte ajaibnya menggunakan fileutilitas mengagumkan yang dikombinasikan dengan kekuatan find, ini bisa berguna:

$ # 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: $@"' -- @@

Keluaran:

file is ASCII: ./text.txt

Legenda: $adalah shell prompt interaktif tempat kita memasukkan perintah kita

Anda dapat memodifikasi bagian setelah &&memanggil beberapa skrip lain atau melakukan beberapa hal lain secara inline juga, yaitu jika file itu berisi string yang diberikan, cat seluruh file atau cari string sekunder di dalamnya.

Penjelasan:

  • find item yang merupakan file
  • Jadikan xargsumpan setiap item sebagai satu baris menjadi satu baris bash perintah / skrip
  • filememeriksa jenis file dengan byte ajaib, grepmemeriksa apakah ASCII ada, jika demikian, kemudian setelah &&perintah berikutnya dijalankan.
  • findmencetak hasil nullterpisah, ini bagus untuk menghindari nama file dengan spasi dan meta-karakter di dalamnya.
  • xargs, menggunakan -0opsi, membacanya secara nullterpisah, -I @@ mengambil setiap record dan digunakan sebagai parameter posisi / args untuk skrip bash.
  • --untuk bashmemastikan apa pun yang muncul setelahnya adalah argumen meskipun dimulai dengan -like -cyang dapat diartikan sebagai opsi bash

Jika Anda perlu mencari tipe selain ASCII, cukup ganti grep ASCIIdengan tipe lain, sepertigrep "PDF document, version 1.4"

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

Gunakan perintah find untuk mendaftar semua file, gunakan perintah file untuk memverifikasi bahwa mereka adalah teks (bukan tar, key), terakhir gunakan perintah awk untuk memfilter dan mencetak hasilnya.

Roy Zeng
sumber
-4

Bagaimana dengan ini

 find . -type f|xargs grep "needle text"
Navi
sumber
Ini tidak terlihat"needle text"
peoro
@Navi: contoh yang disediakan OP hanya menemukan file yang berisi"needl text"
peoro
3
@Navi: sekarang tidak mencari file teks lagi: jika file biner berisi "needle text"itu akan ditemukan
peoro
Mengapa saya bahkan mendengarkan Anda?
Navi
1
@Navi: one-liner Anda tidak memeriksa jenis file dan juga memiliki masalah besar dengan spasi kosong dalam nama file ...
thkala