grep
ist das falsche Werkzeug für den Job.
Sie sehen die � U+FFFD REPLACEMENT CHARACTER
nicht weil es buchstäblich im Dateiinhalt steht, sondern weil Sie sich eine Binärdatei mit einem Tool angesehen haben, das nur textbasierte Eingaben verarbeiten soll. Die Standardmethode zur Behandlung ungültiger Eingaben (d. h. zufälliger Binärdaten) besteht darin, alles, was in der aktuellen Locale (höchstwahrscheinlich UTF-8) nicht gültig ist, durch U+FFFD zu ersetzen, bevor es auf dem Bildschirm angezeigt wird.
Das heißt, es ist sehr wahrscheinlich, dass ein wörtlicher \xEF\xBF\xBD
(die UTF-8-Bytesequenz für das U+FFFD-Zeichen) kommt nie in der Datei vor. grep
völlig zu Recht, wenn er Ihnen sagt, dass es keinen gibt.
Eine Möglichkeit zu erkennen, ob eine Datei eine unbekannte Binärdatei enthält, ist der file(1)
Befehl:
$ head -c 100 /dev/urandom > rubbish.bin
$ file rubbish.bin
rubbish.bin: data
Für jeden unbekannten Dateityp wird einfach data
angezeigt . Versuchen Sie es
$ file out.txt | grep '^out.txt: data$'
um zu prüfen, ob die Datei wirklich beliebige Binärdateien und damit höchstwahrscheinlich Müll enthält.
Wenn Sie sicherstellen möchten, dass out.txt
nur eine UTF-8-kodierte Textdatei ist, können Sie alternativ iconv
verwenden :
$ iconv -f utf-8 -t utf-16 out.txt >/dev/null
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.txt
ist eine Datei, die entwickelt wurde, um zu zeigen, 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:den Zeichenbereich auf \x00-\x7F
zu begrenzen wird fast alles in dieser Datei ablehnen.
Das ist sehr falsch und wird kein �
entfernen da es keine in dieser Datei gibt .
Durch die Verwendung des in dieser Antwort empfohlenen Tests wird 72.5 %
entfernt der Datei:
$ 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 entworfen wurde, um vollkommen gültige Zeichen anzuzeigen.
Test
Die zweite Datei soll mehrere Grenzfälle ausprobieren, um zu bestätigen, dass utf-8-Lesegeräte gute Arbeit leisten. Es enthält viele Zeichen, die dazu führen, dass ein „�“ angezeigt wird. Aber die andere Antwortempfehlung (die ausgewählte) ist, file
zu verwenden scheitert grob mit dieser Datei. Nur das Entfernen eines Nullbytes (\0
) (was technisch gültiges ASCII ist) und ein \x7f
byte (DEL - delete) (was eindeutig auch ein ASCII-Zeichen ist) ergibt all die für file
gültige Datei Befehl:
$ 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 file
die viele nicht erkennen falsche Zeichen, erkennt und meldet aber auch nicht, dass es sich um eine UTF-8-kodierte Datei handelt.
Und ja, file
kann UTF-8-codierten Text erkennen und melden:
$ echo "ééakjfhhjhfakjfhfhaéá" | file -
/dev/stdin: UTF-8 Unicode text
Auch file
meldet die meisten Steuerzeichen im Bereich von 1 bis 31 nicht als ASCII. Es (file
) meldet einige Bereiche als 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 file
ist kein Werkzeug zum Erkennen von Text, sondern zum Erkennen von Magie Nummern in ausführbaren Programmen oder Dateien.
Die Bereiche file
erkennen, und der entsprechende gemeldete Typ, den ich gefunden habe, war:
-
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-kodierte 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 finden Sie unten.
Vorherige Antwort.
Der Unicode-Wert für das von Ihnen gepostete Zeichen ist:
$ printf '%x\n' "'�"
fffd
Ja, das ist ein Unicode-Zeichen 'REPLACEMENT CHARACTER' (U+FFFD). Das ist ein Zeichen, das verwendet wird, um ungültig zu ersetzen Im Text gefundenes Unicode-Zeichen. Es ist eine "visuelle Hilfe", kein echter Charakter. Um jede vollständige Zeile zu finden und aufzulisten, die ungültiges UNICODE enthält Zeichen verwenden:
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 1
ist die Datei ist sauber, sonst ist sie Null 0
.
Wenn Sie gefragt haben:Wie finde ich den �
? verwenden Sie dann 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 korrekt UTF-8-Text verarbeitet, einfach:
➤ echo "$a" | grep -oP '�'
�
Diese sehr frühe Antwort war für den ursprünglichen Beitrag, der lautete:
Wie man in einem Bash-Skript nach Unicode sucht
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 es "funktioniert" wiedergibt UND wenn die Datei "out.txt" KEIN "�" irgendwo in der Datei enthält, dann würde ich es mögen zu cat out.txt
Versuchen Sie es mit
grep -oP "[^\x00-\x7F]"
mit einem if .. then
Anweisung 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
:zeigt nur den Teil einer Linie, der zu PATTERN passt[^\x00-\x7F]
ist ein regulärer Ausdruck, der einem einzelnen Nicht-ASCII-Zeichen entspricht.[[:ascii:]]
- entspricht einem einzelnen ASCII-Zeichen[^[:ascii:]]
- stimmt mit einem einzelnen Nicht-ASCII-Zeichen überein
in bash
LC_COLLATE=C grep -o '[^ -~]' file