Как преобразовать конец строки Windows в конец строки Unix (CR / LF в LF)


80

Я разработчик Java и использую Ubuntu для разработки. Проект был создан в Windows с Eclipse, и он использует Windows-1252 кодировке .

Для преобразования в UTF-8 я использовал программу перекодирования :

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

Эта команда выдает эту ошибку:

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

Я искал об этом и получил решение в Bash и Windows, Recode: неоднозначный вывод на шаге `data..CR-LF ', и он говорит:

Преобразование окончаний строк из CR / LF в один LF: отредактируйте файл с помощью Vim, дайте команду :set ff=unix и сохраните файл. Перекодировать сейчас должно пройти без ошибок.

Хорошо, но у меня много файлов, из которых нужно удалить символ CR / LF, и я не могу открыть каждый, чтобы это сделать. Vi не предоставляет никаких параметров для командной строки для операций Bash.

Можно ли использовать sed для этого? Как?


recodeвыдает эту ошибку при попытке перекодировать файл со смешанным кодированием новой строки dos ( \r\n- CRLF) и unix ( \nLF). К сожалению fromdos, ранее бинарный файл, в настоящее время является псевдонимом для перекодирования, в котором есть эта проблема.
TMS

ты не можешь сделатьvim +ex_command_one +ex_command_two ... file
дерекдрири

Потрясающе! В awkответах нет решения.
Герольд Брозер

Ответы:


122

Должна быть вызвана программа dos2unix, которая исправит за вас окончания строк. Если его еще нет на вашем компьютере с Linux, он должен быть доступен через диспетчер пакетов.


2
Я установил tofrodos, который предоставляет команду fromdos, но проблема не устранена. fromdos -a GravacaoMessageHelper.java; recode CP1252 ... UTF-8 GravacaoMessageHelper.java возвращает: recode: GravacaoMessageHelper.java не удалось: неоднозначный вывод на шаге `CR-LF..data '
MaikoID

1
@MaikoID: Тогда у вас проблемы посерьезнее. recode в любом случае не должен заботиться о окончании строки, поскольку CR - это просто еще один символ для преобразования. И, похоже, это не заботит мою машину.
cHao 08

1
fromdos- это просто псевдоним recode, и это приведет к ошибке OP, упомянутой в файлах со смешанным кодированием dos (\ r \ n - CRLF) и unix (\ n LF). dos2unixРаботает только универсально.
TMS

1
dos2unix доступен для OS X через homebrew: «brew install dos2unix»
Джозеф Шиди,

1
Просто следить за этим, я столкнулся с той же проблемой , и в конечном итоге с помощью следующего: find ./ -name "*.java" -exec dos2unix {} +.
amracel

85

sed не может соответствовать \ n, потому что завершающий символ новой строки удаляется до того, как строка помещается в пространство шаблона, но может соответствовать \ r, поэтому вы можете преобразовать \ r \ n (dos) в \ n (unix), удалив \ r

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

Предупреждение: это изменит исходный файл

Однако с помощью этого вы не можете перейти с unix EOL на dos или старый mac (\ r). Больше чтения здесь:

Как я могу заменить новую строку (\ n) с помощью sed?


4
+1 Хорошее решение! Но учтите, что sed -iизменится исходный файл ! Поскольку люди не ожидают sedтакого поведения, здесь уместно предупреждение. Не многие люди знают, -iпоэтому они будут пытаться sed -i ... file > file2и не ожидают, что исходный файл будет изменен.
TMS

Не все sedварианты распознают нестандартную символьную последовательность \r. В этом случае попробуйте использовать буквальный символ ctrl-M (во многих оболочках введите ctrl-V ctrl-M, чтобы получить буквальный управляющий символ).
Tripleee

14

На самом деле vim позволяет то, что вы ищете. Введите vim и введите следующие команды:

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

Первая из этих команд устанавливает список аргументов для каждого сопоставления файлов **/*.java, то есть всех файлов Java, рекурсивно. Вторая из этих команд по очереди выполняет следующие действия с каждым файлом в списке аргументов:

  • Устанавливает окончания строк в стиле Unix (вы уже знаете это)
  • Записывает файл, если он был изменен
  • Переход к следующему файлу

Это, вероятно, намного медленнее, чем использование dos2unixв цикле for, но все же приятно знать, как это сделать в Vim!
jpaugh

2
Я :: сердце :: моя энергия. Спасибо тебе за это.
Джоно

9

Команда tr также может сделать это:

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

и должен быть доступен вам.

Вам нужно будет запустить tr из скрипта, поскольку он не может работать с именами файлов. Например, создайте файл 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

Запуск myscript.shобработает все файлы java в текущем каталоге и его подкаталогах.


как мне приспособиться к поиску Web-имени * .java | xargs перекодирует CP1252 ... UTF-8
MaikoID 08

Вам нужно будет запустить tr в сценарии bash, поскольку он не может работать с именами файлов. Я отредактирую свой ответ образцом сценария.
KeithL 08

Спасибо за ответ, но ошибка сохраняется = | Неоднозначный вывод на шаге `CR-LF..data '
MaikoID

7

Я сделаю небольшое исключение из ответа Джичао. Вы действительно можете довольно легко сделать все, о чем он только что говорил. Вместо того, чтобы искать \n, просто ищите возврат каретки в конце строки.

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

Чтобы перейти с unix обратно на dos, просто найдите последний символ в строке и добавьте к нему канал формы. (Я добавлю, -rчтобы упростить это с помощью регулярных выражений grep.)

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

Теоретически файл можно изменить в стиле Mac, добавив код в последний пример, который также добавляет следующую строку ввода к первой строке, пока все строки не будут обработаны. Однако я не буду приводить здесь этот пример.

Предупреждение: -i изменяет фактический файл. Если вы хотите сделать резервную копию, добавьте после нее строку символов -i. Это переместит существующий файл в файл с тем же именем с вашими персонажами, добавленными в конец.


1
Мне нравится ваше предложение, но в нем просто отсутствует заключительная одиночная цитата. Это должно быть: sed -ri 's / (.) $ / \ 1 \ r /' $ {FILE_NAME}
mgouin

1
@mgouin Спасибо, что это заметили. Я добавил недостающую одиночную кавычку.
Джон Чешир

1
Для преобразования LF в CRLF захват какого-либо последнего символа, предшествующего концу строки, не требуется и также может повлиять на производительность. В моем случае достаточно сделать sed -i 's/$/\r/' ${FILE_NAME}...
Thomas Urban

-rВариант не является переносимым; если у тебя sedего нет, может, попробуй -E.
Tripleee

5

Чтобы преодолеть

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

просто решением может быть добавление -fфлага для принудительного преобразования.


0

Вы пробовали найти здесь скрипт Python Брайана Мопина ? (Я немного изменил его, чтобы сделать его более общим)

#!/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()

Вы можете использовать этот скрипт с

$ ./cp1252_utf8.py file_cp1252.sql file_utf8.sql

-1

Вернитесь в Windows, скажите Eclipse, чтобы он изменил кодировку на UTF-8, затем вернитесь в Unix и запустите d2uфайлы.


Хотя, если файлов много, это может быть больше работы, чем вы готовы вложить в нее ...
Джонатан

Что такое d2u и где его найти?
Джеспер Рённ-Йенсен,

Время от времени его переименовывают. Похоже, что Ubuntu называет это fromdosв 10.04, и это часть пакета tofrodos.
Джонатан
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.