grep rekursif tidak mencantumkan kecocokan dari beberapa file
Saya menggunakan GNU grep 3.4 untuk menemukan skrip yang berisi pola tertentu. Untuk ini, saya memanggil grep
secara rekursif seperti itu
grep -rin . -e "pattern"
Polanya hanya sebuah kata, tanpa ekspresi reguler. Yang aneh adalah bahwa output tidak mencantumkan kejadian di beberapa file yang pasti berisi string.
Saya telah mencoba membuka file-file ini vim
dan mencari di sana menggunakan /pattern
dan menemukan polanya. Pengkodean ditampilkan vim
sebagai [dos:utf-8:]
. Ketika saya menyalin baris dan menulisnya ke file baru, grep
perintah di atas mencantumkannya dengan benar.
Mengapa tidak grep
mencantumkan file asli?
Jawaban
Grep (atau setidaknya yang lebih tua) tidak mengerti UTF8. Jadi karakter yang disusun, titik pemenggalan, atau data tak terlihat lainnya dapat membuat grep tidak bersemangat.
Grep juga dipengaruhi oleh nilai $LC_ALL, $LC_CTYPE dan $ LANG.
Gunakan vim untuk menyimpan beberapa baris di sekitar kata yang gagal ditemukan oleh grep, lalu buat hexdump dari file contoh kecil itu. Anda mungkin akan melihat mengapa grep gagal
Anda juga dapat menggunakan perintah vim ( ga
, g8
dll) untuk memeriksa karakter tetapi hex dump mungkin lebih jelas
Saya menemukan masalahnya (dengan bantuan jawaban lain). File 'grep' tidak menunjukkan output apa pun karena sebenarnya tidak utf-8
dikodekan, tetapi utf-16be
. Saya mempelajari ini menggunakan hexdump (kredit untuk @RedGrittyBrick):
hd file_for_which_grep_works_as_expected.txt
menghasilkan
00000000 20 20 20 20 50 61 74 74 65 72 6e 0a | Pattern.|
0000000c
sedangkan
hd file_for_which_grep_fails.txt
kembali
00000000 fe ff 00 50 00 61 00 74 00 74 00 65 00 72 00 6e |...P.a.t.t.e.r.n|
00000010 00 0a |..|
00000012
Jadi, periksa ulang pengkodean dengan
file -i file_for_which_grep_fails.txt
mengidentifikasinya sebagai text/plain; charset=utf-16be
.
Saya gagal untuk mengenali bahwa yang utf-8
ditunjukkan oleh vim
sebenarnya adalah pengkodean buffer , bukan pengkodean file . Pelaksana :set fileencoding
di vim
juga ditampilkan dengan benar fileencoding=utf-16
(ditemukan di sinihttps://superuser.com/a/28783/1210682).
Jadi, masalahnya adalah saya grep
tidak berfungsi pada utf-16
file yang disandikan. Ini sudah dijelaskan di sini:https://superuser.com/a/231471/1210682. Namun, solusi untuk mengonversi utf-16
file menjadi utf-8
sebelumnya grep
tidak berfungsi ketika saya menggunakannya secara rekursif, karena saya tidak tahu sebelumnya file mana yang mungkin utf-8
dan yang mana utf-16
dan sedang mencari melalui banyak file.
Ada solusi yang berbeda, dua di antaranya akan saya jelaskan secara singkat di sini:
Solusi cepat dan kotor yang berhasil bagi saya adalah memperluas pola pencarian untuk menyertakan pola yang cocok dengan
utf-16
versi dan mencari salah satu dari kedua pola tersebut:grep -riPa . -e "pattern|p.a.t.t.e.r.n."
Ini tentu saja sangat terbatas dalam hal kemungkinan pola.
Ada alternatif untuk
grep
likeugrep
atauripgrep
yang (antara lain) bisa menanganiutf-16
file. Saya akhirnya menggunakanripgrep
yang tersedia di repositori paket Ubuntu standar dari 18.04 pada:rg -i "pattern"
Ada diskusi bagus tentang alternatif di sini: https://stackoverflow.com/questions/3752913/grepping-binary-files-and-utf16, di antaranya pendekatan menarik yang mencoba mengubah pola pencarian menjadi utf-16
dan memasukkannya ke grep
. Namun, saya tidak bisa membuatnya bekerja.