Jak mogę usunąć BOM z pliku UTF-8?

63

Mam plik w kodowaniu UTF-8 z BOM i chcę usunąć BOM. Czy istnieją jakieś narzędzia wiersza polecenia systemu Linux do usunięcia BOM z pliku?

$ file test.xml
test.xml:  XML 1.0 document, UTF-8 Unicode (with BOM) text, with very long lines
m13r
źródło
1
Kilka miesięcy temu stworzyłem bardzo proste narzędzie, aby to zrobić: oskog97.com/read/?path=/small-scripts/killbom&referer=/… Może warto zainstalować coś takiego w / usr / local / bin, jeśli masz wiele plików zakodowanych w UTF-8 z BOM.
Oskar Skog

Odpowiedzi:

76

Jeśli nie masz pewności, czy plik zawiera BOM UTF-8, to (przy założeniu implementacji GNU sed) usunie BOM, jeśli istnieje, lub nie wprowadzi żadnych zmian, jeśli nie będzie.

sed '1s/^\xEF\xBB\xBF//' < orig.txt > new.txt

Możesz również zastąpić istniejący plik -iopcją:

sed -i '1s/^\xEF\xBB\xBF//' orig.txt
CSM
źródło
4
może to nie działać w ustawieniach regionalnych utf8, ale wcześniejsze zastąpienie ustawień narodowych do c lub posix zawsze będzie działać.
hildred
3
@hildred Przetestowałem to z en_US.UTF-8ustawieniami regionalnymi i działało. Kiedy to zawiedzie?
m13r
2
@ m13r, To zależy od wersji sed i opcji kompilacji. W przypadku awarii bardzo nowa wersja sed z klasami znaków Unicode wprowadzi trzy bajtową sekwencję jako pojedynczy znak, który nie pasuje do sekwencji trzech znaków. Jednak w takim przypadku możesz wykonać szesnastobitowe dopasowanie znaków. Jest to jednak nowa funkcja, która nie występuje powszechnie. Jeśli chcesz przetestować, polecam skompilowanie najnowszej wersji.
hildred
4
Aby to naprawić, aby działało z sedem z obsługą Unicode, wykonaj LC_ALL = C sed '1s / ^ \ xEF \ xBB \ xBF //'
Joshua
@CSM fajnie, ale w jednym specjalnym przypadku nie działa: Bevore: -<U+FEFF>\chapter{xxx}Po: +\chapter{xxx}^M Objaśnienie: Używanie słowa MS do literówek w pliku lateksu. Lateks pod Linuksem pokazuje wspomniane błędy. Dane wyjściowe pochodzą z systemu git. Jak mogę zmienić wyrażenie, aby uchwycić ten szczególny przypadek?
Cutton Eye,
64

LM nie ma sensu w UTF-8. Są one zazwyczaj dodawane przez pomyłkę przez fałszywe oprogramowanie w systemach operacyjnych Microsoft.

dos2unix usunie go, a także zadba o inne osobliwości plików tekstowych Windows.

dos2unix test.xml
Stéphane Chazelas
źródło
17
Zgadzam się, że BOM kodowany w UTF-8 nie ma sensu, ale wierzcie lub nie, jest wiele osób, które uważają, że to świetny pomysł, który pomaga odróżnić UTF-8 od innych kodowań 8-bitowych. To kwestia gustu. Notatnik Windows celowo dodaje zestawienie komponentów.
Johan Myréen,
17
Jakie znaczenie ma to, czy ma sens, czy kontekst jest tylko pytaniem, jak go usunąć? Według Wikipedii Notatnik wymaga, aby BOM rozpoznał plik jako UTF-8, a Dokumenty Google również dodają go podczas eksportowania pliku jako tekstu. Wątpię, czy wszyscy to robią przez pomyłkę .
ilkkachu
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
terdon
1
Czy istnieje sposób, aby nie konwertować zakończeń linii i po prostu usunąć zestawienie komponentów dos2unix?
m13r,
2
@ m13r Następnie użyj skryptu sed w tej odpowiedzi . To usunie tylko BOM (jeśli istnieje), nic więcej nie zostanie zmienione.
Strzałka
25

Możliwe jest usunięcie BOM z pliku za pomocą tailpolecenia:

tail -c +4 withBOM.txt > withoutBOM.txt
m13r
źródło
2
Dlaczego 4? LM ma 3 bajty.
deviantfan
10
@deviantfan Dlatego musisz zacząć od czwartego bajtu, jeśli chcesz go pominąć.
Stéphane Chazelas
9
tailużywa indeksowania opartego na 1 ?! WTF!
CodesInChaos
5
@CodesInChaos, tail -c -1lub tail -c 1(co tailjest zwykle używane) to treść zaczynająca się od ostatniego bajtu, tail -c +1zaczynająca się od pierwszego bajtu. tail -c 0/ tail -c +0ponieważ byłoby to o wiele bardziej nieintuicyjne.
Stéphane Chazelas
2
@deviantfan: (dd bs=1 count=3 of=/dev/null; cat) <input >output. Lub z GNU (head -c3 >/dev/null; cat)- nawet w UTF8 lub innych ustawieniach narodowych innych niż jednobajtowe; GNU head robi „char” = bajt.
dave_thompson_085
20

Korzystanie z VIM

  1. Otwórz plik w VIM:

    vi text.xml
    
  2. Usuń kodowanie BOM:

    :set nobomb
    
  3. Zapisz i wyjdź:

    :wq
    
Joshua Pinter
źródło
Dziwnie z vimem 8 na Macu, mam plik csv utf-8 stworzony przez Excela i zaczyna się od <feff>, ale :set nobombgo nie modyfikuje ani nie usuwa.
dlamblin,
5

Możesz użyć

LANG=C LC_ALL=C sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- filename

aby usunąć znak kolejności bajtów z początku pliku, jeśli taki istnieje, a także przekonwertować dowolne nowe wiersze CR LF tylko na LF. LANG=C LC_ALL=CMówi powłoce chcesz polecenie do uruchomienia w lokalizacji domyślnej C (znany również jako domyślna POSIX locale), gdzie trzy bajty tworzące Byte Order Mark traktowane są jako bajty. -iOpcja sed znaczy w miejscu. Jeśli używasz -i.old, to sed zapisuje oryginalny plik jako filename.old, a nowy plik (z ewentualnymi modyfikacjami) jako filename.


Osobiście lubię to mieć jako ~/bin/fix-ms; na przykład jako

#!/bin/dash
export LANG=C LC_ALL=C
if [ $# -gt 0 ]; then
    for FILE in "$@" ; do
        sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$FILE" || exit 1
    done
else
    exec sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//'
fi

więc jeśli muszę to zastosować, aby powiedzieć wszystkie pliki źródłowe C i nagłówki (na przykład mój stary kod z ery MS-DOS!), po prostu uruchamiam

find . -name '*.[CHch]' -print0 | xargs -r0 ~/bin/ms-fix

lub, jeśli chcę tylko spojrzeć na taki plik, bez modyfikacji, mogę uruchomić

~/bin/ms-fix < filename | less

i nie widzę brzydkiego <U+FEFF>w moim terminalu UTF-8.

Nominalne zwierzę
źródło
Dlaczego nie po prostu sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"?
Stéphane Chazelas
@ StéphaneChazelas: Ponieważ chcę, aby skrypt natychmiast zakończył działanie, jeśli wystąpi problem z zamianą, która sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"nie działa; zwraca kod wyjścia, ale przed wyjściem przetwarza wszystkie pliki wymienione na liście argumentów.
Nominal Animal
@ StéphaneChazelas: --Przed nazwami plików jest oczywiście ważne: bez nich nazwy plików zaczynające się od myślnika mogą być uważane za opcje przez sed. Zredagowałem je w mojej odpowiedzi; dziekuje za przypomnienie!
Nominal Animal
0

Niedawno znalazłem to małe narzędzie wiersza polecenia, które dodaje lub usuwa BOM w dowolnych plikach zakodowanych w UTF-8: UTF BOM Utils ( nowy link na github)

Mała wada, możesz pobrać tylko zwykły kod źródłowy C ++. Musisz utworzyć plik makefile ( na przykład z CMake ) i skompilować go samodzielnie, na tej stronie nie ma plików binarnych.

Wernfried Domscheit
źródło