it-swarm.com.de

Wie kann ich feststellen, ob eine Datei eine UTF-8-Stückliste in Bash enthält?

Ich versuche, ein Skript zu schreiben, das UTF-8-Stücklisten automatisch aus einer Datei entfernt. Ich habe Probleme beim Erkennen, ob die Datei überhaupt eine Datei hat oder nicht. Hier ist mein Code:

function has-bom {
    # Test if the file starts with 0xEF, 0xBB, and 0xBF
    head -c 3 "$1" | grep -P '\xef\xbb\xbf'
    return $?
}

Aus irgendeinem Grund scheint head die Stückliste vor der Datei zu ignorieren. Als Beispiel das ausführen

printf '\xef\xbb\xbf' > file
head -c 3 file

druckt nichts.

Ich habe versucht, nach einer Option in head --help zu suchen, mit der ich umgehen könnte, aber kein Glück. Kann ich irgendetwas tun, um dies zu erreichen?

17
James Ko

Lassen Sie uns zunächst zeigen, dass head tatsächlich korrekt funktioniert:

$ printf '\xef\xbb\xbf' >file
$ head -c 3 file 
$ head -c 3 file | hexdump -C
00000000  ef bb bf                                          |...|
00000003

Nun erstellen wir eine Arbeitsfunktion has_bom. Wenn Ihre grep-P unterstützt, ist eine Option:

$ has_bom() { head -c3 "$1" | LC_ALL=C grep -qP '\xef\xbb\xbf'; }
$ has_bom file && echo yes
yes

Derzeit unterstützt nur GNU grep-P.

Eine andere Option ist die Verwendung von bashs $'...':

$ has_bom() { head -c3 "$1" | grep -q $'\xef\xbb\xbf'; }
$ has_bom file && echo yes
yes

ksh und zsh unterstützen auch $'...', aber dieses Konstrukt ist nicht POSIX und dash unterstützt es nicht.

Anmerkungen:

  1. Die Verwendung eines expliziten return $? ist optional. Die Funktion gibt standardmäßig den Exit-Code des letzten Befehlslaufs zurück.

  2. Ich habe das POSIX-Formular zur Definition von Funktionen verwendet. Dies entspricht der Bash-Form, bietet jedoch ein weniger Problem, wenn Sie die Funktion unter einer anderen Shell ausführen müssen.

  3. bash akzeptiert die Verwendung des Zeichens - in einem Funktionsnamen, dies ist jedoch eine umstrittene Funktion. Ich habe es durch _ ersetzt, was allgemein akzeptiert wird. (Weitere Informationen zu diesem Thema finden Sie unter diese Antwort .)

  4. Die -q-Option für grep macht den Befehl leise, was bedeutet, dass immer noch ein ordnungsgemäßer Beendigungscode festgelegt wird, aber keine Zeichen an stdout gesendet werden.

16
John1024

Ich habe das Folgende für die erste Lesezeile angewendet:

read c
if (( "$(printf "%d" "'${c:0:1}")" == 65279 ))  ; then c="${c:1}" ; fi

Dadurch wird die Stückliste einfach aus der Variablen entfernt.

0
apexik