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
не удается с этим файлом. Только удаление нулевого byte ( \0
) (который технически является действительным ASCII) и \x7f
байта (DEL - delete) (который также явно является символом 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
долго понимает юникод (что делает его намного медленнее, поэтому поиск строк asciiLANG=C grep
- огромное улучшение производительности).