GNU/Linux >> Belajar Linux >  >> Linux

Cara grep untuk unicode � dalam skrip bash

grep adalah alat yang salah untuk pekerjaan itu.

Anda melihat � U+FFFD REPLACEMENT CHARACTER bukan 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 dengan mengganti semua yang tidak valid di lokal saat ini (kemungkinan besar UTF-8) dengan U+FFFD sebelum menyentuh layar.

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

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

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

Untuk jenis file yang tidak diketahui, hanya akan tertulis data . Coba

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

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

Jika Anda ingin memastikan bahwa out.txt adalah file teks berenkode UTF-8 saja, sebagai alternatif, Anda dapat menggunakan iconv :

$ iconv -f utf-8 -t utf-16 out.txt >/dev/null

TL;DR:

grep -axv '.*' out.txt 

jawaban panjang

Kedua jawaban yang ada sangat menyesatkan dan pada dasarnya salah.

Untuk menguji, Dapatkan dua file ini (dari pengembang yang sangat terkenal: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

UTF-8-demo.txt pertama adalah file yang dirancang untuk menunjukkan seberapa baik UTF-8 mampu menampilkan banyak bahasa, matematika, 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 ke \x00-\x7F akan menolak hampir semua yang ada di dalam file ini.
Itu sangat salah dan tidak akan menghapus karena tidak ada di file itu .

Menggunakan tes yang direkomendasikan dalam jawaban itu akan menghapus 72.5 % dari 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 sebagian besar tujuan 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. Ini berisi di dalam banyak karakter yang akan menyebabkan '�' ditampilkan. Tapi rekomendasi jawaban lain (yang terpilih) menggunakan file gagal total dengan file ini. Hanya menghapus nol byte (\0 ) (yang secara teknis adalah ASCII yang valid) dan \x7f byte (DEL - hapus) (yang jelas merupakan karakter ASCII juga) akan membuat semua file yang valid untuk file perintah:

$ 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 file gagal mendeteksi banyak karakter yang salah, tetapi juga gagal mendeteksi dan melaporkan bahwa itu adalah file berenkode UTF-8.

Dan ya, file dapat mendeteksi dan melaporkan teks berenkode UTF-8:

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

Juga, file gagal 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 file bukan alat untuk mendeteksi teks, tetapi untuk mendeteksi sihir angka dalam program atau file yang dapat dijalankan.

Rentang file deteksi, dan jenis terkait yang dilaporkan yang saya temukan adalah:

  • Nilai satu byte, kebanyakan 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 berenkode 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.

Jawaban Sebelumnya.

Nilai Unicode untuk karakter yang Anda posting adalah:

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

Ya, itu adalah Karakter Unicode 'KARAKTER PENGGANTI' (U+FFFD). Itu adalah karakter yang digunakan untuk mengganti tidak valid Karakter Unicode ditemukan dalam teks. Ini adalah "bantuan visual", bukan karakter nyata. Untuk menemukan dan mencantumkan setiap baris lengkap yang berisi UNICODE yang tidak valid penggunaan karakter:

grep -axv '.*' out.txt 

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

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

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

Jika yang Anda tanyakan adalah:bagaimana menemukan karakter, kemudian, 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 '�'
�

Jawaban paling awal ini untuk postingan asli yaitu:

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 pun di file, saya ingin gema "berfungsi" DAN jika file "out.txt" TIDAK berisi "�" di mana pun di file, maka saya akan menyukainya untuk cat out.txt

Coba

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

dengan if .. then pernyataan sebagai berikut:

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

Penjelasan:

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

di bash

LC_COLLATE=C grep -o '[^ -~]' file

Linux
  1. Bisakah Skrip Bash Dihubungkan ke File?

  2. Bagaimana Cara Men-debug Skrip Bash?

  3. Cara membuat perintah alias berfungsi di skrip bash atau file bashrc

  1. Bagaimana cara menyorot skrip Bash di Vim?

  2. Cara mengganti spasi pada nama file menggunakan skrip bash

  3. Bagaimana cara mengurai file CSV di Bash?

  1. Bagaimana Cara Memeriksa Substring Di Shell Script Bash?

  2. Bagaimana cara 'menangkap' aliran berkelanjutan?

  3. Bagaimana cara memahami konten setelah pola?