Как найти Unicode в скрипте bash

10
if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt
fi

По сути, если файл «out.txt» содержит « » в любом месте файла, я бы хотел, чтобы он отображал «рабочий» И если файл «out.txt» НЕ содержит « » где-либо в файле, я хотел бы это кошка из .txt

РЕДАКТИРОВАТЬ: Так вот что я делаю. Я пытаюсь грубой силой расшифровать openssl.

openssl enc возвращает 0 в случае успеха, ненулевое значение в противном случае. Примечание: вы получите ложные срабатывания, потому что AES / CBC может только определить, работает ли «дешифрование» на основе правильного заполнения. Таким образом, файл расшифровывается, но он не будет правильным паролем, поэтому в нем будет бред. Общий характер в тарабарщине это " ". Поэтому я хочу, чтобы цикл do продолжал работать, если вывод содержит « ».

Вот моя git ссылка https://github.com/Raphaeangelo/OpenSSLCracker Вот сценарий

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null && printf "==================================================\n"
if grep -q "�" out.txt
    then
        :
    else
        cat out.txt &&
            printf "\n==================================================" &&
            printfn"\npassword is $line\n" &&
            read -p "press return key to continue..." < /dev/tty; 
fi
done < ./password.txt

он все еще показывает мне вывод с charicter в нем

ОБНОВЛЕНИЕ: решено

printf "Working..."

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null
if file out.txt | grep -q 'out.txt: ASCII text'
    then
        printf "\n==================================================\n\n" &&
            cat out.txt &&
            printf "\n==================================================" &&
            printf "\npassword is $line\n" && 
            read -p "press return key to continue..." < /dev/tty;
    else
        : 
fi
done < ./password.txt
Стюарт Слоун
источник
Это выглядит правильно, это должно работать (кстати, у меня нет шрифта для вашего символа юникода, чтобы увидеть, но ни один из них не имеет никакого особого значения). grepдолго понимает юникод (что делает его намного медленнее, поэтому поиск строк ascii LANG=C grep- огромное улучшение производительности).
Петер - Восстановить Монику
Возможно, мне придется удалить это и опубликовать еще один вопрос, потому что я уверен, что я полностью запутал всех здесь.
Стюарт Слоун
@ Стюарт Слоан, заголовок твоего вопроса How to grep for unicode � in a bash script- это действительно то, что ты хочешь? извлечь Unicode? пожалуйста, уточните, чтобы мы могли помочь!
1
@Goro Я внес изменения в свой оригинальный пост. Я надеюсь, что это имеет смысл. Пожалуйста, дайте мне знать, если это не так, и я постараюсь уточнить.
Стюарт Слоун
1
Оба настоящих ответа вводят в заблуждение. Пожалуйста, прочитайте (снова) мой ответ , я отредактировал его, чтобы объяснить, что не так с обоими ответами.
Исаак

Ответы:

27

grep это неправильный инструмент для работы.

Вы видите U+FFFD REPLACEMENT CHARACTERне потому, что оно находится буквально в содержимом файла, а потому, что вы посмотрели на двоичный файл с помощью инструмента, который должен обрабатывать только текстовый ввод. Стандартный способ обработки недопустимого ввода (т. Е. Случайных двоичных данных) состоит в замене всего, что недопустимо в текущей локали (наиболее вероятно, UTF-8), на U + FFFD до того, как оно попадет на экран.

Это означает, что весьма вероятно, что литерал \xEF\xBF\xBD(последовательность байтов UTF-8 для символа U + FFFD) никогда не встречается в файле. grepсовершенно правильно сказать, что нет.

Один из способов определить, содержит ли файл какой-либо неизвестный бинарный файл, с помощью file(1)команды:

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

Для любого неизвестного типа файла это просто скажет data. Пытаться

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

проверить, действительно ли файл содержит произвольный двоичный файл и, следовательно, скорее всего мусор.

Если вы хотите убедиться, что out.txtэто только текстовый файл в кодировке UTF-8, вы можете использовать iconv:

$ iconv -f utf-8 -t utf-16 out.txt >/dev/null
Boldewyn
источник
Вы совершенно правы! К сожалению, я все еще получаю (меньше, чем раньше) мусор на выходе.
Стюарт Слоун
Возможно, fileобнаруживает некоторый другой тип контента для этих файлов. Если 100% всегда ожидать только UTF-8 закодированных текстовых файлов, вы можете проверить с iconv, если файл является допустимым UTF-8: iconv -f utf-8 -t utf-16 out.txt >/dev/null. Если iconvне удается преобразовать файл из-за недопустимых последовательностей UTF-8, он вернется с ненулевым кодом завершения.
Болдевин
2
Команда файла была правильной! Вы помогли мне решить мою проблему, спасибо!
Стюарт Слоун
4
Конечно, что grep "это инструмент для работы", попробуйте grep -axv '.*' badchars.txt. Это напечатает любую строку, которая содержит недопустимый символ Unicode .
Исаак
1
Это чрезвычайно вводит в заблуждение, пожалуйста, прочитайте в моем ответе о том, что fileделает.
Исаак
5

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 '�'
�
Исаак
источник
OMG большое спасибо за grep -axv '.*' !! Я боролся с несколькими плохими символами в моих текстовых файлах, и как исправить их в emacs, в течение десяти или двух лет !!!
nealmcb
3

Этот очень ранний ответ был для оригинального сообщения, которое было:

Как найти Unicode в скрипте bash

if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt  fi

По сути, если файл «out.txt» содержит « » в любом месте файла, я бы хотел, чтобы он отображал «рабочий» И если файл «out.txt» НЕ содержит « » где-либо в файле, я хотел бы это кошка из .txt

Пытаться

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

со if .. thenследующим заявлением:

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

Explanation💡:

  • -P, --perl-regexp: PATTERN является регулярным выражением Perl
  • -o, --only-matching: показать только часть строки, соответствующую PATTERN
  • [^\x00-\x7F] является регулярным выражением для соответствия одному не-ASCII символу
  • [[:ascii:]] - соответствует одному символу ASCII
  • [^[:ascii:]] - соответствует одному не-ASCII-символу

в bash

LC_COLLATE=C grep -o '[^ -~]' file
Тоби Спейт
источник
3
Это сломается (будет иметь ложный положительный результат), как только кто-то не говорит по-английски ...
Кевин
или если кто-то пытается обсудить à la carte, emoji, Pokémon или что-то еще, не строго ограниченное 7-битным ASCII. Лучше искать что-нибудь в 00-1F, кроме 09 0A 0D (табуляция, перевод строки, возврат каретки).
Алькаро
Это очень плохая идея. Это отклонит любой допустимый символ Unicode выше диапазона ASCII, только немногим более миллиона допустимых символов. Удивительный. Попробуйте: printf '%b' "$(printf '\\U%x' {128..131})" | grep -oP "[^\x00-\x7F]"просто 4 действительных символа Unicode, которые ваш код отклоняет. :-(
Исаак
Это чрезвычайно вводящий в заблуждение ответ. Пожалуйста, прочитайте в моем ответе, почему упрощенный подход к ограничению только ASCII терпит неудачу.
Исаак