Jak mogę znaleźć wszystkie pliki tekstowe zakodowane w UTF-16 w drzewie katalogów za pomocą polecenia Unix?

6

Chcę użyć polecenia powłoki Unix znaleźć wszystkie UTF-16 plików zakodowanych (zawierający UTF-16 Byte Order Mark ( BOM )) w drzewie katalogów. Czy istnieje polecenie, którego mogę użyć?

Jochen
źródło

Odpowiedzi:

8

Chociaż poprosiłeś o znalezienie BOM, użycie filemoże nawet dać wyniki, gdy taka LM nie jest obecna. Od man file:

Jeśli plik nie pasuje do żadnego z wpisów w pliku magicznym, jest sprawdzany, czy nie jest plikiem tekstowym. ASCII, ISO-8859-x, 8-bitowe zestawy znaków rozszerzonych ASCII bez ISO (takie jak używane w systemach Macintosh i IBM PC), kodowanie Unicode kodowane w UTF-8, kodowanie Unicode w kodowaniu UTF-16 i zestawy znaków EBCDIC można wyróżnić różnymi zakresami i sekwencjami bajtów, które stanowią tekst do druku w każdym zestawie. Jeśli plik przejdzie którykolwiek z tych testów, raportowany jest jego zestaw znaków.

Stąd na przykład:

odnaleźć . -type f -exec plik --mime {} | grep "charset = utf-16"
Arjan
źródło
1

Możesz użyć grep:

 grep -rl $(echo -ne '^\0376\0377') *

(Testowane z bashi GNU grep, może współpracować z innymi.)

Wyjaśnienie:

Część $ (echo ... generuje BOM (Hex FE FF, jako ósemkowe sekwencje ucieczki), jest następnie podawana grepjako wzorzec, poprzedzony '^' (= początek dopasowania linii).

-r to wyszukiwanie rekurencyjne, -l sprawia, że ​​grep wypisuje nazwy znalezionych plików (zamiast dopasowanej linii).

Może to być trochę marnotrawne, ponieważ grep całkowicie skanuje każdy plik, a nie tylko początek. Jeśli to głównie małe pliki tekstowe, nie ma to znaczenia. Jeśli masz mnóstwo plików z kilkoma MB, będziesz musiał napisać skrypt perla :-).

Alternatywnie możesz spróbować file(w połączeniu z find + xargs). filezidentyfikuje UTF-16 (jako „dane znaków Unicode UTF-16”). Nie wiem jednak, jak to jest niezawodne (ponieważ wykorzystuje heurystykę).

sleske
źródło
1
„... jak grep całkowicie przeskanuje każdy plik ...” - tylko ci, którzy nie pasują. -lsprawia, że grepzatrzymuje się na pierwszym wystąpieniu. Z -Ijednym powoduje również grepignorowanie plików binarnych.
Daniel Andersson
1

Oto skrypt, którego używam do znajdowania plików UTF-16, a następnie konwertowania ich na UTF-8. #! / bin / sh

find ./ -type f |
while read file; do
    if [ "`head -c 2 -- "$file"`" == $'\xff\xfe' ]
    then
        echo "Problems with: $file"
        # If you want to convert to UTF-8 uncomment these lines.
        #cat "$file" | iconv -f UTF-16 -t UTF-8 > "$file.tmp"
        #mv -f "$file.tmp" "$file"
    fi
done

źródło
1

Jeśli go masz, możesz użyć enca:

enca -L none * 2>/dev/null | grep  -i "Universal character"
użytkownik31894
źródło
0

Dzięki za pomoc wszystkim. To, co działało najlepiej na moim Macu, to:

find . -type f -exec awk -F '\n' '/^\xFE\xFF|\xFF\xFE/ { print FILENAME; nextfile } { nextfile }' {} \;

Opiera się na rozwiązaniu sleske, ale bierze pod uwagę, że znak kolejności bajtów można odwrócić. Używa również awk, aby przestać szukać BOM po pierwszej linii, ponieważ BOM musi znajdować się na początku pliku. E ucieczka używana do określenia BOM działa z bash, nie wiem, czy działa z innymi powłokami.

Narzędzie enca zaproponowane przez ghostdog74 również wykona zadanie, ale nie było go na moim Macu.

Jochen
źródło