Jak przekonwertować koniec wiersza systemu Windows na koniec wiersza w systemie Unix (CR / LF na LF)

80

Jestem programistą Java i używam Ubuntu do programowania. Projekt został stworzony w Windows z Eclipse i używa kodowania Windows-1252 .

Aby przekonwertować do UTF-8, użyłem programu recode :

find Web -iname \*.java | xargs recode CP1252...UTF-8

To polecenie powoduje ten błąd:

recode: Web/src/br/cits/projeto/geral/presentation/GravacaoMessageHelper.java failed: Ambiguous output in step `CR-LF..data

Szukałem tego i otrzymałem rozwiązanie w Bash i Windows, Recode: Niejednoznaczne wyjście w kroku `data..CR-LF ' i mówi:

Konwertuj zakończenia linii z CR / LF na pojedynczy LF: Edytuj plik za pomocą Vima, podaj polecenie :set ff=unixi zapisz plik. Przekodowywanie powinno teraz działać bez błędów.

Fajnie, ale mam wiele plików, z których mogę usunąć znak CR / LF, i nie mogę otworzyć każdego, aby to zrobić. Vi nie zapewnia żadnej opcji w wierszu poleceń dla operacji Bash.

Czy można do tego użyć seda? W jaki sposób?

MaikoID
źródło
recodepowoduje ten błąd podczas próby przekodowania pliku z mieszanym kodowaniem nowej linii dos ( \r\n- CRLF) i unix ( \nLF). Niestety fromdos, dawniej plik binarny jest obecnie aliasem do przekodowywania, który ma ten problem.
TMS,
nie możesz tego zrobićvim +ex_command_one +ex_command_two ... file
derekdreery
Zadziwiający! W odpowiedziach nie ma awkrozwiązania.
Gerold Broser

Odpowiedzi:

122

Powinien istnieć program o nazwie dos2unix, który naprawi zakończenia linii. Jeśli nie ma go jeszcze na twoim Linuksie, powinien być dostępny za pośrednictwem menedżera pakietów.

cHao
źródło
2
Zainstalowałem tofrodos, które zapewniają polecenie fromdos, ale problem nadal występuje. fromdos -a GravacaoMessageHelper.java; recode CP1252 ... UTF-8 GravacaoMessageHelper.java zwraca: recode: GravacaoMessageHelper.java nie powiodło się: Niejednoznaczne dane wyjściowe w kroku `CR-LF..data '
MaikoID
1
@MaikoID: Wtedy masz większe problemy. recode i tak nie powinno przejmować się zakończeniami linii, ponieważ CR to tylko kolejny znak do konwersji. I wydaje się, że nie obchodzi go mój komputer.
cHao
1
fromdosjest tylko aliasem do recode, co spowoduje błąd OP wspomniany w plikach z mieszanym kodowaniem dos (\ r \ n - CRLF) i unix (\ n LF). dos2unixDziała tylko uniwersalnie.
TMS
1
dos2unix jest dostępny na OS X przez homebrew: "brew install dos2unix"
Joseph Sheedy
1
Wystarczy śledzić na to, wpadłem na ten sam problem, co skończyło się stosując następujący: find ./ -name "*.java" -exec dos2unix {} +.
amracel
85

sed nie może dopasować \ n, ponieważ końcowy znak nowej linii jest usuwany przed umieszczeniem linii w przestrzeni wzorca, ale może dopasować \ r, więc możesz przekonwertować \ r \ n (dos) na \ n (unix), usuwając \ r

sed -i 's/\r//g' file

Ostrzeżenie: spowoduje to zmianę oryginalnego pliku

Nie możesz jednak zmienić unixowego EOL na DOS lub starego mac (\ r) przez to. Więcej lektur tutaj:

Jak mogę zamienić znak nowej linii (\ n) używając seda?

Jichao
źródło
4
+1 To fajne rozwiązanie! Należy jednak pamiętać, że sed -izmieni to oryginalny plik ! Ponieważ ludzie nie spodziewaliby sedsię, że tak się zachowają, ostrzeżenie jest tutaj właściwe. Niewiele osób wie, -iwięc będą próbować sed -i ... file > file2i nie oczekiwać, że oryginalny plik zostanie zmodyfikowany.
TMS,
Nie wszystkie sedwarianty rozpoznają niestandardową sekwencję symboliczną \r. W takim przypadku spróbuj użyć literału ctrl-M (w wielu powłokach wpisz ctrl-V ctrl-M, aby utworzyć znak kontrolny literału).
tripleee
14

W rzeczywistości vim pozwala na to, czego szukasz. Wpisz vim i wpisz następujące polecenia:

:args **/*.java
:argdo set ff=unix | update | next

Pierwsze z tych poleceń **/*.javarekurencyjnie ustawia listę argumentów na wszystkie pasujące pliki , czyli wszystkie pliki Java. Drugie z tych poleceń wykonuje kolejno następujące czynności dla każdego pliku na liście argumentów:

  • Ustawia zakończenia linii na styl uniksowy (już to wiesz)
  • Zapisuje plik, jeśli został zmieniony
  • Przechodzi do następnego pliku
Arandur
źródło
Jest to prawdopodobnie znacznie wolniejsze niż użycie dos2unixw pętli for, ale nadal dobrze jest wiedzieć, jak to zrobić w Vimie!
jpaugh
2
Ja :: serce :: moja vim. Dziękuję Ci za to.
Jono,
9

Polecenie tr może również zrobić to:

tr -d '\15\32' < winfile.txt > unixfile.txt

i powinien być dla Ciebie dostępny.

Będziesz musiał uruchomić tr z poziomu skryptu, ponieważ nie może on działać z nazwami plików. Na przykład utwórz plik myscript.sh:

#!/bin/bash

for f in `find -iname \*.java`; do
    echo "$f"
    tr -d '\15\32' < "$f" > "$f.tr"
    mv "$f.tr" "$f"
    recode CP1252...UTF-8 "$f"
done

Uruchomienie myscript.shspowoduje przetworzenie wszystkich plików java w bieżącym katalogu i jego podkatalogach.

KeithL
źródło
jak mogę się dostosować, aby znaleźć nazwę sieci Web * .java | xargs recode CP1252 ... UTF-8
MaikoID
Musiałbyś uruchomić tr w skrypcie bash, ponieważ nie może on działać na nazwach plików. Zmienię odpowiedź za pomocą przykładowego skryptu.
KeithL
Dziękuję za odpowiedź, ale błąd nadal występuje = | Niejednoznaczne dane wyjściowe w kroku `CR-LF..data '
MaikoID
7

Zrobię mały wyjątek od odpowiedzi jichao. Właściwie możesz zrobić wszystko, o czym właśnie mówił, dość łatwo. Zamiast \nszukać znaku, po prostu poszukaj powrotu karetki na końcu wiersza.

sed -i 's/\r$//' "${FILE_NAME}"

Aby zmienić z unixowego z powrotem na dos, po prostu poszukaj ostatniego znaku w linii i dodaj do niego feed. (Dodam, -raby było to łatwiejsze dzięki wyrażeniom regularnym grep).

sed -ri 's/(.)$/\1\r/' "${FILE_NAME}"

Teoretycznie plik można zmienić na styl mac, dodając kod do ostatniego przykładu, który również dołącza następny wiersz danych wejściowych do pierwszego wiersza, aż wszystkie wiersze zostaną przetworzone. Jednak nie będę próbował tutaj robić tego przykładu.

Ostrzeżenie: -i zmienia rzeczywisty plik. Jeśli chcesz wykonać kopię zapasową, dodaj ciąg znaków po -i. Spowoduje to przeniesienie istniejącego pliku do pliku o tej samej nazwie z twoimi znakami dodanymi na końcu.

John Chesshir
źródło
1
Podoba mi się twoja sugestia, ale brakuje jej tylko jednego cytatu zamykającego. Powinien to być: sed -ri 's / (.) $ / \ 1 \ r /' $ {
NAZWA PLIKU
1
@mgouin Dzięki, że to zauważyłeś. Dodałem brakujący pojedynczy cytat.
John Chesshir
1
Aby przekonwertować LF na CRLF, przechwytywanie ostatniego znaku przed końcem wiersza nie jest wymagane i może mieć również wpływ na wydajność. W moim przypadku wystarczy sed -i 's/$/\r/' ${FILE_NAME}...
Thomas Urban
Ta -ropcja nie jest przenośna; jeśli sedgo nie masz, może spróbuj -E.
tripleee
5

Aby przezwyciężyć

Ambiguous output in step `CR-LF..data'

prostym rozwiązaniem może być dodanie -fflagi wymuszającej konwersję.

V_V
źródło
0

Czy próbowałeś znaleźć tutaj skrypt Pythona autorstwa Bryana Maupina ? (Zmodyfikowałem to trochę, aby było bardziej ogólne)

#!/usr/bin/env python

import sys

input_file_name = sys.argv[1]
output_file_name = sys.argv[2]

input_file = open(input_file_name)
output_file = open(output_file_name, 'w')

line_number = 0

for input_line in input_file:
    line_number += 1
    try:  # first try to decode it using cp1252 (Windows, Western Europe)
        output_line = input_line.decode('cp1252').encode('utf8')
    except UnicodeDecodeError, error:  # if there's an error
        sys.stderr.write('ERROR (line %s):\t%s\n' % (line_number, error))  # write to stderr
        try:  # then if that fails, try to decode using latin1 (ISO 8859-1)         
            output_line = input_line.decode('latin1').encode('utf8')
        except UnicodeDecodeError, error:  # if there's an error
            sys.stderr.write('ERROR (line %s):\t%s\n' % (line_number, error))  # write to stderr
            sys.exit(1)  # and just keep going
    output_file.write(output_line)

input_file.close()
output_file.close()

Możesz użyć tego skryptu z

$ ./cp1252_utf8.py file_cp1252.sql file_utf8.sql
Anthony O.
źródło
-1

Wróć do systemu Windows, powiedz Eclipse, aby zmienił kodowanie na UTF-8, a następnie z powrotem na Unix i uruchom d2una plikach.

Jonathan
źródło
Chociaż jeśli jest dużo plików, może to wymagać więcej pracy, niż jesteś gotów w to włożyć ...
Jonathan
Co to jest d2u i gdzie go znaleźć?
Jesper Rønn-Jensen
Czasami jest zmieniana nazwa. Wygląda na to, że Ubuntu nazywa to fromdosw 10.04 i jest częścią pakietu tofrodos.
Jonathan