Bagaimana cara grep untuk unicode dalam skrip bash

10
if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt
fi

Pada dasarnya, jika file "out.txt" berisi " " di mana saja di dalam file, saya ingin menggemakan "berfungsi" DAN jika file "out.txt" TIDAK mengandung " " di mana saja dalam file, maka saya ingin ke cat out.txt

EDIT: Jadi inilah yang saya lakukan. Saya mencoba untuk memaksa mendekripsi openssl.

openssl enc mengembalikan 0 pada keberhasilan, bukan nol sebaliknya. Catatan: Anda akan mendapatkan hasil positif palsu karena AES / CBC hanya dapat menentukan apakah "dekripsi berhasil" berdasarkan pada mendapatkan padding yang benar. Jadi file tersebut didekripsi tetapi itu tidak akan menjadi kata sandi yang benar sehingga akan memiliki omong kosong di dalamnya. Karakter umum dalam omong kosong adalah " ". Jadi saya ingin loop do terus berjalan jika output mengandung " ".

Inilah tautan git saya https://github.com/Raphaeangelo/OpenSSLCracker Inilah skripnya

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null && printf "==================================================\n"
if grep -q "�" out.txt
    then
        :
    else
        cat out.txt &&
            printf "\n==================================================" &&
            printfn"\npassword is $line\n" &&
            read -p "press return key to continue..." < /dev/tty; 
fi
done < ./password.txt

masih menunjukkan saya output dengan charicter di dalamnya

PEMBARUAN: Dipecahkan

printf "Working..."

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null
if file out.txt | grep -q 'out.txt: ASCII text'
    then
        printf "\n==================================================\n\n" &&
            cat out.txt &&
            printf "\n==================================================" &&
            printf "\npassword is $line\n" && 
            read -p "press return key to continue..." < /dev/tty;
    else
        : 
fi
done < ./password.txt
Stuart Sloan
sumber
Kelihatannya benar, seharusnya berfungsi (btw, saya tidak memiliki font untuk dilihat oleh karakter unicode Anda, tetapi tidak satupun dari mereka yang memiliki arti khusus). greplama mengerti unicode (yang membuatnya jauh lebih lambat, jadi untuk mencari string ascii, a LANG=C grepadalah peningkatan kinerja yang sangat besar).
peterh
Saya mungkin harus menghapus ini dan mengirim pertanyaan lain karena saya yakin saya benar-benar membingungkan semua orang di sini.
Stuart Sloan
@Stuart Sloan judul pertanyaan Anda adalah How to grep for unicode � in a bash scriptapakah ini yang benar-benar Anda inginkan? mengekstrak unicode? mohon klarifikasi sehingga kami dapat membantu!
1
@Goro Saya sudah mengedit di posting asli saya. Saya harap ini masuk akal. Tolong beri tahu saya jika tidak dan saya akan mencoba mengklarifikasi.
Stuart Sloan
1
Kedua jawaban ini sangat menyesatkan. Harap baca (lagi) jawaban saya , saya telah mengeditnya untuk menjelaskan apa yang salah dengan kedua jawaban itu.
Isaac

Jawaban:

27

grep adalah alat yang salah untuk pekerjaan itu.

Anda melihat U+FFFD REPLACEMENT CHARACTERbukan karena itu benar-benar dalam konten file, tetapi karena Anda melihat file biner dengan alat yang seharusnya hanya menangani input berbasis teks. Cara standar untuk menangani input yang tidak valid (yaitu, data biner acak) adalah mengganti semua yang tidak valid di lokal saat ini (kemungkinan besar UTF-8) dengan U + FFFD sebelum menyentuh layar.

Itu berarti sangat mungkin bahwa literal \xEF\xBF\xBD(urutan byte UTF-8 untuk karakter U + FFFD) tidak pernah terjadi dalam file. grepsepenuhnya benar dalam memberi tahu Anda, tidak ada.

Salah satu cara untuk mendeteksi apakah suatu file berisi beberapa biner yang tidak dikenal adalah dengan file(1)perintah:

$ head -c 100 /dev/urandom > rubbish.bin
$ file rubbish.bin
rubbish.bin: data

Untuk semua jenis file yang tidak dikenal, itu hanya akan mengatakan data. Mencoba

$ file out.txt | grep '^out.txt: data$'

untuk memeriksa apakah file tersebut benar-benar berisi biner sembarang dan dengan demikian kemungkinan besar adalah sampah.

Jika Anda ingin memastikan bahwa itu out.txtadalah file teks yang disandikan UTF-8 saja, Anda dapat menggunakan iconv:

$ iconv -f utf-8 -t utf-16 out.txt >/dev/null
Boldewyn
sumber
Anda benar sekali! sayangnya, saya masih mendapatkan beberapa (kurang dari sebelumnya) sampah di output.
Stuart Sloan
Mungkin filemendeteksi beberapa tipe konten lain untuk file-file itu. Jika Anda 100% selalu hanya mengharapkan UTF-8 file teks dikodekan, Anda dapat memeriksa dengan iconv, jika file adalah valid UTF-8: iconv -f utf-8 -t utf-16 out.txt >/dev/null. Jika iconvtidak dapat mengonversi file karena urutan UTF-8 tidak valid, itu akan kembali dengan kode keluar yang tidak nol.
Boldewyn
2
Perintah file benar! Anda membantu saya menyelesaikan masalah saya, terima kasih!
Stuart Sloan
4
Tentu saja grep itu "adalah alat untuk pekerjaan itu", cobalah grep -axv '.*' badchars.txt. Itu akan mencetak setiap baris yang berisi Karakter Unicode yang tidak valid .
Isaac
1
Ini sangat menyesatkan, baca jawaban saya tentang apa yang filebisa.
Isaac
5

TL; DR:

grep -axv '.*' out.txt 

jawaban panjang

Kedua jawaban ini sangat menyesatkan dan pada dasarnya salah.

Untuk menguji, Dapatkan dua file ini (dari pengembang yang sangat dihormati: Markus Kuhn):

$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt
$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt

Demo

Yang pertama UTF-8-demo.txtadalah file yang dirancang untuk menunjukkan seberapa baik UTF-8 mampu menyajikan banyak bahasa, matematika, huruf braille dan banyak jenis karakter berguna lainnya. Lihatlah dengan editor teks (yang mengerti utf-8) dan Anda akan melihat banyak contoh dan tidak .

Tes yang diajukan oleh satu jawaban: untuk membatasi rentang karakter \x00-\x7Fakan menolak hampir semua yang ada di dalam file ini.
Itu sangat salah dan tidak akan menghapus apa pun karena tidak ada dalam file itu .

Menggunakan tes yang direkomendasikan dalam jawaban itu akan menghapus 72.5 %file:

$ grep -oP "[^\x00-\x7F]" UTF-8-demo.txt | tr -d '\n' | wc -c
10192
$ cat UTF-8-demo.txt | wc -c
14058

Itu (untuk tujuan paling praktis) seluruh file. File yang dirancang dengan sangat baik untuk menampilkan karakter yang benar-benar valid.

Uji

File kedua dirancang untuk mencoba beberapa kasus perbatasan untuk mengonfirmasi bahwa pembaca utf-8 melakukan pekerjaan dengan baik. Berisi di dalam banyak karakter yang akan menyebabkan ' ' ditampilkan. Tetapi rekomendasi jawaban yang lain (yang dipilih) untuk digunakan filegagal total dengan file ini. Hanya menghapus nol byte ( \0) (yang secara teknis ASCII valid) dan \x7fbyte (DEL - delete) (yang jelas merupakan karakter ASCII juga) akan membuat semua file valid untuk fileperintah:

$ cat UTF-8-test.txt | tr -d '\0\177' > a.txt
$ file a.txt 
a.txt: Non-ISO extended-ASCII text, with LF, NEL line terminators

Tidak hanya filegagal mendeteksi banyak karakter yang salah, tetapi juga gagal mendeteksi dan melaporkan bahwa itu adalah file yang disandikan UTF-8.

Dan ya, filedapat mendeteksi dan melaporkan teks yang disandikan UTF-8:

$ echo "ééakjfhhjhfakjfhfhaéá" | file -
/dev/stdin: UTF-8 Unicode text

Juga, filegagal melaporkan sebagai ASCII sebagian besar karakter kontrol dalam rentang 1 hingga 31. Ini ( file) melaporkan beberapa rentang sebagai data:

$ printf '%b' "$(printf '\\U%x' {1..6})" | file -
/dev/stdin: data

Lainnya sebagai ASCII text:

$ printf '%b' "$(printf '\\U%x' 7 {9..12})" | file -
/dev/stdin: ASCII text

Sebagai rentang karakter yang dapat dicetak (dengan baris baru):

$ printf '%b' "$(printf '\\U%x' {32..126} 10)" | file -
/dev/stdin: ASCII text

Tetapi beberapa rentang dapat menyebabkan hasil yang aneh:

$ printf '%b' "$(printf '\\U%x' {14..26})" | file -
/dev/stdin: Atari MSA archive data, 4113 sectors per track, starting track: 5141, ending track: 5655

Program fileini bukan alat untuk mendeteksi teks, tetapi untuk mendeteksi angka ajaib dalam program atau file yang dapat dieksekusi.

Rentang filemendeteksi, dan jenis yang sesuai yang dilaporkan yang saya temukan adalah:

  • Nilai satu byte, sebagian besar ascii:

    {1..6} {14..26} {28..31} 127   :data
    {128..132} {134..159}          :Non-ISO extended-ASCII text
    133                            :ASCII text, with LF, NEL line terminators
    27                             :ASCII text, with escape sequences
    13                             :ASCII text, with CR, LF line terminators
    8                              :ASCII text, with overstriking
    7 {9..12} {32..126}            :ASCII text
    {160..255}                     :ISO-8859 text
    
  • Rentang terenkode utf-8:

    {1..6} {14..26} {28..31} 127   :data
    27                             :ASCII text, with escape sequences
    13                             :ASCII text, with CR, LF line terminators
    8                              :ASCII text, with overstriking
    7 {9..12} {32..126}            :ASCII text
    {128..132} {134..159}          :UTF-8 Unicode text
    133                            :UTF-8 Unicode text, with LF, NEL line terminators
    {160..255}                     :UTF-8 Unicode text
    {256..5120}                    :UTF-8 Unicode text
    

Salah satu solusi yang mungkin ada di bawah ini.


Jawaban Sebelumnya.

Nilai Unicode untuk karakter yang Anda posting adalah:

$ printf '%x\n' "'�"
fffd

Ya, itu adalah Karakter Unicode 'REPLACEMENT CHARACTER' (U + FFFD) . Itu adalah karakter yang digunakan untuk mengganti karakter Unicode tidak valid yang ditemukan dalam teks. Ini adalah "bantuan visual", bukan karakter nyata. Untuk menemukan dan mendaftar setiap baris penuh yang berisi karakter UNICODE yang tidak valid, gunakan:

grep -axv '.*' out.txt 

tetapi jika Anda hanya ingin mendeteksi jika ada karakter yang tidak valid, gunakan:

grep -qaxv '.*' out.txt; echo $?

Jika hasilnya 1file bersih, jika tidak akan menjadi nol 0.


Jika yang Anda tanyakan adalah: bagaimana menemukan karakter, maka, gunakan ini:

➤ a='Basically, if the file "out.txt" contains "�" anywhere in the file I'
➤ echo "$a" | grep -oP $(printf %b \\Ufffd)
�

Atau jika sistem Anda memproses teks UTF-8 dengan benar, cukup:

➤ echo "$a" | grep -oP '�'
�
Ishak
sumber
OMG terima kasih banyak untuk grep -axv '.*' !! Saya telah berjuang dengan beberapa karakter buruk dalam file teks saya, dan bagaimana cara memperbaikinya dalam emacs, selama satu atau dua dekade !!!
nealmcb
3

Jawaban paling awal ini adalah untuk pos asli yaitu:

Bagaimana cara grep untuk unicode dalam skrip bash

if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt  fi

Pada dasarnya, jika file "out.txt" berisi " " di mana saja di dalam file, saya ingin menggemakan "berfungsi" DAN jika file "out.txt" TIDAK mengandung " " di mana saja dalam file, maka saya ingin ke cat out.txt

Mencoba

grep -oP "[^\x00-\x7F]"

dengan if .. thenpernyataan sebagai berikut:

if grep -oP "[^\x00-\x7F]" file.txt; then
    echo "grep found something ..."
else
    echo "Nothing found!"
fi

Penjelasan💡:

  • -P, --perl-regexp: POLA adalah ekspresi reguler Perl
  • -o, --only-matching: hanya menampilkan bagian dari POLA yang cocok dengan garis
  • [^\x00-\x7F] adalah regex untuk mencocokkan karakter non-ASCII tunggal.
  • [[:ascii:]] - Cocok dengan satu karakter ASCII
  • [^[:ascii:]] - Cocok dengan satu karakter non-ASCII

di bash

LC_COLLATE=C grep -o '[^ -~]' file
Toby Speight
sumber
3
Ini akan pecah (memiliki false positive) segera setelah seseorang tidak berbicara bahasa Inggris ...
Kevin
atau jika seseorang mencoba mendiskusikan à la carte, emoji, Pokémon, atau apa pun yang tidak terbatas pada 7bit ASCII. Lebih baik mencari apa pun di 00-1F, kecuali 09 0A 0D (tab, linefeed, carriage return).
Alcaro
Ini adalah ide yang sangat buruk. Ini akan menolak setiap arang Unicode berlaku di atas rentang ASCII, hanya hanya sedikit lebih dari satu juta karakter yang valid. Luar biasa. Coba: printf '%b' "$(printf '\\U%x' {128..131})" | grep -oP "[^\x00-\x7F]"Hanya 4 karakter Unicode yang valid yang ditolak oleh kode Anda. :-(
Isaac
Ini adalah jawaban yang sangat menyesatkan. Harap baca jawaban saya mengapa pendekatan sederhana untuk membatasi hanya pada ASCII gagal total.
Isaac