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


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

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

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

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
    

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.


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.