TL; DR:
grep -axv '.*' out.txt
คำตอบยาว
คำตอบปัจจุบันทั้งสองมีความเข้าใจผิดอย่างมากและผิดโดยทั่วไป
ในการทดสอบรับไฟล์สองไฟล์นี้ (จากนักพัฒนาที่ได้รับการยอมรับเป็นอย่างดี: 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
การสาธิต
สิ่งแรกUTF-8-demo.txt
คือไฟล์ที่ถูกออกแบบมาเพื่อแสดงว่า UTF-8 สามารถนำเสนอภาษา, คณิตศาสตร์, อักษรเบรลล์และอักขระที่มีประโยชน์อื่น ๆ อีกมากมายได้อย่างไร ลองดูด้วยโปรแกรมแก้ไขข้อความ (นั่นเข้าใจ UTF-8) และคุณจะเห็นจำนวนมากตัวอย่างและไม่มี �
การทดสอบที่คำตอบเดียวเสนอ: เพื่อ จำกัด ช่วงของตัวอักษรเพื่อ\x00-\x7F
จะปฏิเสธเกือบทุกอย่างภายในไฟล์นี้
มันผิดมากและจะไม่ลบไฟล์ใด ๆ�
เนื่องจากไม่มีอยู่ในไฟล์นั้น
การใช้การทดสอบที่แนะนำในคำตอบนั้นจะเป็นการลบ72.5 %
ไฟล์:
$ grep -oP "[^\x00-\x7F]" UTF-8-demo.txt | tr -d '\n' | wc -c
10192
$ cat UTF-8-demo.txt | wc -c
14058
นั่นคือ (สำหรับการใช้งานจริง) ไฟล์ทั้งหมด ไฟล์ที่ออกแบบมาอย่างดีเพื่อแสดงอักขระที่ใช้ได้อย่างสมบูรณ์แบบ
ทดสอบ
ไฟล์ที่สองได้รับการออกแบบมาเพื่อทดลองใช้เคสขนาดเล็กเพื่อยืนยันว่าเครื่องอ่าน utf-8 ทำงานได้ดี มันมีอยู่ภายในตัวละครมากมายที่จะทำให้ ' ' ที่จะแสดง แต่ข้อเสนอแนะคำตอบอื่น ๆ (อันที่เลือก) เพื่อใช้file
ล้มเหลวอย่างไม่มีการลดกับไฟล์นี้ เฉพาะการลบศูนย์ไบต์ ( \0
) (ซึ่งเป็นเทคนิคที่ถูกต้อง ASCII) และ\x7f
ไบต์ (DEL - ลบ) (ซึ่งเป็นอักขระ ASCII อย่างชัดเจนเช่นกัน) จะทำให้ไฟล์ทั้งหมดที่ถูกต้องสำหรับfile
คำสั่ง:
$ 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
ไม่เพียง แต่file
ตรวจไม่พบอักขระที่ไม่ถูกต้องจำนวนมากแต่ยังไม่สามารถตรวจจับและรายงานว่าเป็นไฟล์ที่เข้ารหัส UTF-8
และใช่file
สามารถตรวจจับและรายงานข้อความที่เข้ารหัส UTF-8 ได้:
$ echo "ééakjfhhjhfakjfhfhaéá" | file -
/dev/stdin: UTF-8 Unicode text
นอกจากนี้file
ไม่สามารถรายงานเป็น ASCII ของอักขระควบคุมส่วนใหญ่ในช่วง 1 ถึง 31 ได้ ( file
) รายงานบางช่วงdata
ดังนี้:
$ printf '%b' "$(printf '\\U%x' {1..6})" | file -
/dev/stdin: data
คนอื่น ๆ เป็นASCII text
:
$ printf '%b' "$(printf '\\U%x' 7 {9..12})" | file -
/dev/stdin: ASCII text
เป็นช่วงอักขระที่พิมพ์ได้ (พร้อมบรรทัดใหม่):
$ printf '%b' "$(printf '\\U%x' {32..126} 10)" | file -
/dev/stdin: ASCII text
แต่บางช่วงอาจทำให้ได้ผลลัพธ์ที่แปลก:
$ printf '%b' "$(printf '\\U%x' {14..26})" | file -
/dev/stdin: Atari MSA archive data, 4113 sectors per track, starting track: 5141, ending track: 5655
โปรแกรมfile
ไม่ได้เป็นเครื่องมือในการตรวจจับข้อความ แต่เพื่อตรวจจับหมายเลขเวทย์มนตร์ในโปรแกรมหรือไฟล์ปฏิบัติการ
ช่วงการfile
ตรวจจับและประเภทที่สัมพันธ์กันที่ฉันรายงานพบคือ:
หนึ่งไบต์ค่าส่วนใหญ่ 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
ช่วงที่เข้ารหัส 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
ทางออกหนึ่งที่เป็นไปได้อยู่ด้านล่าง
คำตอบก่อนหน้า
ค่า Unicode สำหรับตัวละครที่คุณกำลังโพสต์คือ:
$ printf '%x\n' "'�"
fffd
ใช่ว่าเป็นอักขระ Unicode 'แทนอักขระตัว' (U + FFFD) นั่นคืออักขระที่ใช้เพื่อแทนที่อักขระ Unicode ที่ไม่ถูกต้องที่พบในข้อความ มันเป็น "เครื่องช่วยมองเห็น" ไม่ใช่ตัวละครที่แท้จริง ในการค้นหาและแสดงรายการทุกบรรทัดที่มีอักขระUNICODE ที่ไม่ถูกต้องให้ใช้:
grep -axv '.*' out.txt
แต่ถ้าคุณต้องการตรวจสอบว่าอักขระใดไม่ถูกต้องให้ใช้:
grep -qaxv '.*' out.txt; echo $?
หากผลเป็นไฟล์ที่สะอาดมิฉะนั้นจะเป็นศูนย์1
0
หากสิ่งที่คุณถามคือวิธีการค้นหา�
ตัวละครแล้วใช้สิ่งนี้:
➤ a='Basically, if the file "out.txt" contains "�" anywhere in the file I'
➤ echo "$a" | grep -oP $(printf %b \\Ufffd)
�
หรือหากระบบของคุณประมวลผลข้อความ UTF-8 อย่างถูกต้องเพียง:
➤ echo "$a" | grep -oP '�'
�
grep
เข้าใจ unicode นาน (ซึ่งทำให้ช้าลงมากดังนั้นในการค้นหาสตริง ascii aLANG=C grep
เป็นการปรับปรุงประสิทธิภาพครั้งใหญ่)