Як грепнути за unicode у баш-скрипті


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

В основному, якщо файл "out.txt" містить " " в будь-якому місці файлу, я хотів би, щоб він повторювався "робочим" І якщо файл "out.txt" НЕ містить " " ніде у файлі, то я хотів би це для котів out.txt

EDIT: Отже, ось що я роблю. Я намагаюся грубо примусити розшифрувати opensl.

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

Це виглядає правильно, він повинен працювати (btw, я не маю шрифту для вашого символу Unicode, але жоден з них не має особливого значення). grepдовго розуміє unicode (що робить його набагато повільніше, тому для пошуку рядків ascii, LANG=C grepце величезне підвищення продуктивності).
петерх

Можливо, мені доведеться видалити це та поставити ще одне запитання, тому що я впевнений, що тут я абсолютно заплутав усіх.
Стюарт Слоун

@Stuart Sloan назва вашого питання How to grep for unicode � in a bash script- це справді те, що ви хочете? витягнути унікод? прошу уточнити, щоб ми могли допомогти!

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

Ви абсолютно праві! на жаль, я все ще отримую трохи (менше, ніж раніше) сміття на виході.
Стюарт Слоун

Можливо, fileвиявляє якийсь інший тип вмісту для цих файлів. Якщо 100% завжди очікувати тільки UTF-8 закодованих текстових файлів, ви можете перевірити з iconv, якщо файл є допустимим UTF-8: iconv -f utf-8 -t utf-16 out.txt >/dev/null. Якщо iconvнеможливо перетворити файл через недійсні послідовності UTF-8, він повернеться з ненульовим кодом виходу.
Болдевін

2
Команда файлів була правильною! Ви допомогли мені вирішити моє питання дякую!
Стюарт Слоун

4
Звичайно, що греп "є інструментом для роботи", спробуйте 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не вдається з цим файлом грубо. Тільки видалення нульового байта ( \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 '�'
�

OMG дуже дякую за grep -axv '.*' !! Я боровся з кількома поганими персонажами в своїх текстових файлах, і як їх виправити в emacs, десятиліття-два !!!
nealmcb

3

Ця дуже рання відповідь була для початкової публікації, яка була:

Як грепнути за unicode у баш-скрипті

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

В основному, якщо файл "out.txt" містить " " в будь-якому місці файлу, я хотів би, щоб він повторювався "робочим" І якщо файл "out.txt" НЕ містить " " ніде у файлі, то я хотів би це для котів out.txt

Спробуйте

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

із if .. thenзаявою:

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

Пояснення💡:

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

в bash

LC_COLLATE=C grep -o '[^ -~]' file

3
Це порушиться (мати помилковий позитив), як тільки хтось не розмовлятиме англійською ...
Кевін

або якщо хтось намагається обговорити а-ля-карт, емоджі, покемони чи що-небудь інше, не суворо обмежене 7-бітовим ASCII. Краще шукайте що-небудь у 00-1F, за винятком 09 0A 0D (вкладка, підводка, повернення вагона).
Алькаро

Це дуже вірна погана ідея. Це відхилить будь-які дійсні символи Unicode вище діапазону ASCII, лише трохи більше мільйона дійсних символів. Дивовижний. Спробуйте: printf '%b' "$(printf '\\U%x' {128..131})" | grep -oP "[^\x00-\x7F]"Всього 4 дійсних символи Unicode, які ваш код відхиляє. :-(
Ісаак

Це вкрай оманлива відповідь. Будь ласка, прочитайте у моїй відповіді, чому спрощений підхід обмеження лише ASCII грубо не вдається.
Ісаак
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.