So suchen Sie in einem Bash-Skript nach Unicode


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

Grundsätzlich, wenn die Datei "out.txt" irgendwo in der Datei " " enthält, möchte ich, dass sie "funktioniert" wiedergibt UND wenn die Datei "out.txt" NICHT " " irgendwo in der Datei enthält, dann möchte ich es zu cat out.txt

EDIT: Also hier ist was ich tue. Ich versuche, eine openssl-Entschlüsselung brutal zu erzwingen.

openssl enc gibt bei Erfolg 0 zurück, andernfalls ungleich Null. Hinweis: Sie erhalten falsch positive Ergebnisse, da AES / CBC nur anhand der richtigen Auffüllung feststellen kann, ob "Entschlüsselung funktioniert". Die Datei entschlüsselt also, aber es wird nicht das richtige Passwort sein, so dass es Kauderwelsch enthält. Ein häufiges Zeichen im Kauderwelsch ist " ". Ich möchte also, dass die do-Schleife weiter läuft, wenn die Ausgabe " " enthält.

Hier ist mein Git-Link https://github.com/Raphaeangelo/OpenSSLCracker Hier ist das Skript

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

Es zeigt mir immer noch die Ausgabe mit dem -Zeichen darin

UPDATE: Gelöst

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

Es sieht richtig aus, es sollte funktionieren (übrigens habe ich keine Schriftart für Ihr Unicode-Zeichen, aber keine von ihnen hat eine besondere Bedeutung). greplange versteht Unicode (was es viel langsamer macht, so dass die Suche nach ASCII-Strings LANG=C grepeine enorme Leistungsverbesserung ist).
Peter - Wiedereinsetzung Monica

Möglicherweise muss ich dies löschen und eine weitere Frage stellen, da ich sicher bin, dass ich alle hier völlig verwirre.
Stuart Sloan

@ Stuart Sloan Der Titel Ihrer Frage lautet: Ist das How to grep for unicode � in a bash scriptwirklich das, was Sie wollen? den Unicode extrahieren? Bitte klären Sie, damit wir Ihnen helfen können!

1
@Goro Ich habe die Bearbeitung meines ursprünglichen Beitrags vorgenommen. Ich hoffe es macht Sinn. Bitte lassen Sie mich wissen, wenn dies nicht der Fall ist, und ich werde versuchen, dies zu klären.
Stuart Sloan

1
Beide vorliegenden Antworten sind äußerst irreführend. Bitte lesen Sie (noch einmal) meine Antwort , ich habe sie bearbeitet, um zu erklären, was mit beiden Antworten falsch ist.
NotAnUnixNazi

Antworten:


27

grep ist das falsche Werkzeug für den Job.

Sie sehen das U+FFFD REPLACEMENT CHARACTERnicht, weil es buchstäblich im Dateiinhalt enthalten ist, sondern weil Sie eine Binärdatei mit einem Tool betrachtet haben, das nur textbasierte Eingaben verarbeiten soll. Die Standardmethode für die Behandlung ungültiger Eingaben (dh zufälliger Binärdaten) besteht darin, alles, was im aktuellen Gebietsschema (höchstwahrscheinlich UTF-8) nicht gültig ist, durch U + FFFD zu ersetzen, bevor es auf den Bildschirm gelangt.

Das heißt, es ist sehr wahrscheinlich, dass ein Literal \xEF\xBF\xBD(die UTF-8-Byte-Sequenz für das U + FFFD-Zeichen) niemals in der Datei vorkommt. grepEs ist völlig richtig, Ihnen zu sagen, dass es keine gibt.

Eine Möglichkeit, festzustellen, ob eine Datei eine unbekannte Binärdatei enthält, ist der folgende file(1)Befehl:

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

Für jeden unbekannten Dateityp wird einfach gesagt data. Versuchen

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

um zu überprüfen, ob die Datei wirklich eine beliebige Binärdatei und damit höchstwahrscheinlich Müll enthält.

Wenn Sie das sicherstellen möchten out.txt es sich nur um eine UTF-8-codierte Textdatei handelt, können Sie alternativ Folgendes verwenden iconv:

$ iconv -f utf-8 -t utf-16 out.txt >/dev/null

Du bist genau richtig! Leider bekomme ich immer noch etwas (weniger als zuvor) Müll in der Ausgabe.
Stuart Sloan

fileErkennt möglicherweise einen anderen Inhaltstyp für diese Dateien. Wenn Sie immer zu 100% nur UTF-8-codierte Textdateien erwarten, können Sie überprüfen iconv, ob eine Datei gültig ist. UTF-8 : iconv -f utf-8 -t utf-16 out.txt >/dev/null. Wenn iconvdie Datei aufgrund ungültiger UTF-8-Sequenzen nicht konvertiert werden kann, wird sie mit einem Exit-Code ungleich Null zurückgegeben.
Boldewyn

2
Der Dateibefehl war richtig! Sie haben mir geholfen, mein Problem zu lösen, danke!
Stuart Sloan

4
Natürlich, dass grep "das Werkzeug für den Job ist", versuchen Sie es grep -axv '.*' badchars.txt. Dadurch wird jede Zeile gedruckt, die ein ungültiges Unicode- Zeichen enthält.
NotAnUnixNazi

1
Dies ist äußerst irreführend. Bitte lesen Sie in meiner Antwort, was das filebedeutet.
NotAnUnixNazi

5

TL; DR:

grep -axv '.*' out.txt 

lange Antwort

Beide vorliegenden Antworten sind äußerst irreführend und grundsätzlich falsch.

Holen Sie sich zum Testen diese beiden Dateien (von einem sehr angesehenen Entwickler: 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

Demo

Die erste UTF-8-demo.txtist eine Datei, die zeigen soll, wie gut UTF-8 viele Sprachen, Mathematik, Braille und viele andere nützliche Zeichentypen darstellen kann. Werfen Sie einen Blick mit einem Texteditor (der utf-8 versteht) und Sie werden viele Beispiele sehen und nein .

Der Test, den eine Antwort vorschlägt: Um den Zeichenbereich auf zu beschränken, \x00-\x7Fwird fast alles in dieser Datei abgelehnt.
Das ist sehr falsch und wird keine entfernen, da es keine in dieser Datei gibt .

Wenn Sie den in dieser Antwort empfohlenen Test verwenden, wird 72.5 %die Datei entfernt:

$ grep -oP "[^\x00-\x7F]" UTF-8-demo.txt | tr -d '\n' | wc -c
10192
$ cat UTF-8-demo.txt | wc -c
14058

Das ist (für die meisten praktischen Zwecke) die gesamte Datei. Eine Datei, die sehr gut gestaltet ist, um perfekt gültige Zeichen anzuzeigen.

Prüfung

Die zweite Datei soll mehrere Grenzfälle versuchen, um zu bestätigen, dass utf-8-Leser gute Arbeit leisten. Es enthält viele Zeichen, die dazu führen, dass ein ' ' angezeigt wird. Die andere Antwortempfehlung (die ausgewählte), die verwendet werden soll, fileschlägt bei dieser Datei jedoch grob fehl. Nur das Entfernen eines Null-Bytes ( \0) (das technisch als ASCII gültig ist) und eines \x7fBytes (DEL - delete) (das eindeutig auch ein ASCII-Zeichen ist) macht die gesamte Datei für den fileBefehl gültig :

$ 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

Nicht nur fileversäumt es, die vielen zu erkennen falschen Zeichen , sondern es wird auch nicht erkannt und gemeldet, dass es sich um eine UTF-8-codierte Datei handelt.

Und ja, filekann UTF-8-codierten Text erkennen und melden:

$ echo "ééakjfhhjhfakjfhfhaéá" | file -
/dev/stdin: UTF-8 Unicode text

Außerdem werden die filemeisten Steuerzeichen im Bereich von 1 bis 31 nicht als ASCII gemeldet. fileEinige Bereiche werden wie folgt gemeldet data:

$ printf '%b' "$(printf '\\U%x' {1..6})" | file -
/dev/stdin: data

Andere als ASCII text:

$ printf '%b' "$(printf '\\U%x' 7 {9..12})" | file -
/dev/stdin: ASCII text

Als druckbarer Zeichenbereich (mit Zeilenumbrüchen):

$ printf '%b' "$(printf '\\U%x' {32..126} 10)" | file -
/dev/stdin: ASCII text

Einige Bereiche können jedoch zu seltsamen Ergebnissen führen:

$ printf '%b' "$(printf '\\U%x' {14..26})" | file -
/dev/stdin: Atari MSA archive data, 4113 sectors per track, starting track: 5141, ending track: 5655

Das Programm fileist kein Werkzeug zum Erkennen von Text, sondern zum Erkennen magischer Zahlen in ausführbaren Programmen oder Dateien.

Die erkannten Bereiche fileund der entsprechende Typ, den ich gefunden habe, waren:

  • Ein-Byte-Werte, meistens 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-codierte Bereiche:

    {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
    

Eine mögliche Lösung liegt unten.


Vorherige Antwort.

Der Unicode-Wert für das Zeichen, das Sie veröffentlichen, lautet:

$ printf '%x\n' "'�"
fffd

Ja, das ist ein Unicode-Zeichen 'REPLACEMENT CHARACTER' (U + FFFD) . Dies ist ein Zeichen, das verwendet wird, um ungültige Unicode-Zeichen im Text zu ersetzen . Es ist eine "visuelle Hilfe", kein wirklicher Charakter. Um jede vollständige Zeile zu finden und aufzulisten , die ungültige UNICODE- Zeichen enthält , verwenden Sie:

grep -axv '.*' out.txt 

Wenn Sie jedoch nur feststellen möchten, ob ein Zeichen ungültig ist, verwenden Sie:

grep -qaxv '.*' out.txt; echo $?

Wenn das Ergebnis ist, dass 1die Datei sauber ist, ist sie ansonsten Null 0.


Wenn Sie gefragt haben, wie Sie den Charakter finden, verwenden Sie Folgendes:

➤ a='Basically, if the file "out.txt" contains "�" anywhere in the file I'
➤ echo "$a" | grep -oP $(printf %b \\Ufffd)
�

Oder wenn Ihr System UTF-8-Text korrekt verarbeitet, einfach:

➤ echo "$a" | grep -oP '�'
�

OMG vielen Dank für grep -axv '.*' !! Ich habe ein oder zwei Jahrzehnte lang mit ein paar schlechten Zeichen in meinen Textdateien zu kämpfen gehabt und wie man sie in Emacs repariert !!!
Nealmcb

3

Diese sehr frühe Antwort war für den ursprünglichen Beitrag, der lautete:

So suchen Sie in einem Bash-Skript nach Unicode

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

Grundsätzlich, wenn die Datei "out.txt" irgendwo in der Datei " " enthält, möchte ich, dass sie "funktioniert" wiedergibt UND wenn die Datei "out.txt" NICHT " " irgendwo in der Datei enthält, dann möchte ich es zu cat out.txt

Versuchen

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

mit einer if .. thenAussage wie folgt:

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

Erklärung💡:

  • -P, --perl-regexp: PATTERN ist ein regulärer Perl-Ausdruck
  • -o, --only-matching : Nur den Teil einer Zeile anzeigen, der mit MUSTER übereinstimmt
  • [^\x00-\x7F] ist ein regulärer Ausdruck für ein einzelnes Nicht-ASCII-Zeichen.
  • [[:ascii:]] - Entspricht einem einzelnen ASCII-Zeichen
  • [^[:ascii:]] - Entspricht einem einzelnen Nicht-ASCII-Zeichen

im bash

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

3
Dies wird brechen (falsch positiv), sobald jemand kein Englisch spricht ...
Kevin

oder wenn jemand versucht, à la carte, Emoji, Pokémon oder etwas anderes zu diskutieren, das nicht ausschließlich auf 7-Bit-ASCII beschränkt ist. Suchen Sie in 00-1F besser nach etwas anderem als 09 0A 0D (Registerkarte, Zeilenvorschub, Wagenrücklauf).
Alcaro

Das ist eine sehr schlechte Idee. Dadurch werden alle gültigen Unicode-Zeichen über dem ASCII-Bereich abgelehnt , nur etwas mehr als eine Million gültige Zeichen. Tolle. Versuchen Sie: printf '%b' "$(printf '\\U%x' {128..131})" | grep -oP "[^\x00-\x7F]"Nur 4 gültige Unicode-Zeichen, die Ihr Code ablehnt. :-(
NotAnUnixNazi

Dies ist eine äußerst irreführende Antwort. Bitte lesen Sie in meiner Antwort, warum der vereinfachte Ansatz, nur auf ASCII zu beschränken, grob fehlschlägt.
NotAnUnixNazi
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.