TL; DR:
grep -axv '.*' out.txt
довга відповідь
Обидві відповіді вкрай вводять в оману і в основному неправильні.
Для тестування дістаньте ці два файли (від дуже високо оціненого розробника: Маркуса Куна):
$ 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,LANG=C grep
це величезне підвищення продуктивності).