Как конвертировать DOS/Windows newline (CRLF) в Unix newline (LF) в сценарий Bash?

Как я могу программным способом (т.е. не использовать vi) конвертировать строки DOS/Windows в Unix?

Команды dos2unix и unix2dos недоступны в некоторых системах. Как я могу имитировать их с помощью команд типа sed/awk/tr?

Ответ 1

Вы можете использовать tr для преобразования из DOS в Unix; однако вы можете сделать это только безопасно, если CR появляется в вашем файле только как первый байт пары байтов CRLF. Это обычно так. Затем вы используете:

tr -d '\015' <DOS-file >UNIX-file

Обратите внимание, что имя DOS-file отличается от имени UNIX-file; если вы попытаетесь использовать одно и то же имя дважды, вы не получите никаких данных в файле.

Вы не можете сделать это наоборот (со стандартным "tr" ).

Если вы знаете, как ввести возврат каретки в script (control-V, control-M, чтобы ввести control-M), тогда:

sed 's/^M$//'     # DOS to Unix
sed 's/$/^M/'     # Unix to DOS

где '^ M' является символом control-M. Вы также можете использовать механизм bash dos2unix и unix2dos, или, возможно, dtou и utod) и используйте их.

Ответ 2

tr -d "\r" < file

посмотрите здесь для примеров, используя sed:

# IN UNIX ENVIRONMENT: convert DOS newlines (CR/LF) to Unix format.
sed 's/.$//'               # assumes that all lines end with CR/LF
sed 's/^M$//'              # in bash/tcsh, press Ctrl-V then Ctrl-M
sed 's/\x0D$//'            # works on ssed, gsed 3.02.80 or higher

# IN UNIX ENVIRONMENT: convert Unix newlines (LF) to DOS format.
sed "s/$/`echo -e \\\r`/"            # command line under ksh
sed 's/$'"/`echo \\\r`/"             # command line under bash
sed "s/$/`echo \\\r`/"               # command line under zsh
sed 's/$/\r/'                        # gsed 3.02.80 or higher

Используйте sed -i для преобразования на месте, например. sed -i 's/..../' file.

Ответ 3

Выполнение этого с помощью POSIX сложно:

  • POSIX Sed не поддерживает \r или \15. Даже если бы это было так, то на месте опция -i не POSIX

  • POSIX Awk поддерживает \r и \15, однако опция -i inplace не POSIX

  • d2u и dos2unix не утилиты POSIX, но ex

  • POSIX ex не поддерживает \r, \15, \n или \12

Чтобы удалить возврат каретки:

ex -bsc '%!awk "{sub(/\r/,\"\")}1"' -cx file

Чтобы добавить возврат каретки:

ex -bsc '%!awk "{sub(/$/,\"\r\")}1"' -cx file

Ответ 4

Используя AWK, вы можете:

awk '{ sub("\r$", ""); print }' dos.txt > unix.txt

Используя Perl, вы можете:

perl -pe 's/\r$//' < dos.txt > unix.txt

Ответ 5

Эта проблема может быть решена с помощью стандартных инструментов, но для неосторожных есть достаточно много ловушек, которые я рекомендую вам установить flip, который был написан более 20 лет назад Рахулом Деси, автором zoo. Он отлично работает, конвертируя форматы файлов, в то время как, например, избегая случайного уничтожения двоичных файлов, что слишком легко, если вы просто участвуете в изменении каждого CRLF, который вы видите...

Ответ 6

Решения, опубликованные до сих пор, касаются только части проблемы, конвертируя DOS/Windows CRLF в Unix LF; часть, которую им не хватает, заключается в том, что DOS использует CRLF в качестве разделителя строк, а Unix использует LF в качестве терминатора линии. Разница в том, что файл DOS (обычно) не будет иметь ничего после последней строки в файле, в то время как Unix будет. Чтобы правильно выполнить преобразование, вам нужно добавить этот финальный LF (если только файл не имеет нулевой длины, то есть вообще не имеет линий). Мое любимое заклинание для этого (с небольшой добавленной логикой для обработки файлов в формате CR, разделенных в стиле Mac, а не для файлов досье, которые уже есть в unix-формате) немного Perl:

perl -pe 'if ( s/\r\n?/\n/g ) { $f=1 }; if ( $f || ! $m ) { s/([^\n])\z/$1\n/ }; $m=1' PCfile.txt

Обратите внимание, что это отправляет Unixified версию файла в stdout. Если вы хотите заменить файл Unixified, добавьте флаг perl -i.

Ответ 7

Если у вас нет доступа к dos2unix, но вы можете прочитать эту страницу, вы можете скопировать/вставить dos2unix.py отсюда.

#!/usr/bin/env python
"""\
convert dos linefeeds (crlf) to unix (lf)
usage: dos2unix.py <input> <output>
"""
import sys

if len(sys.argv[1:]) != 2:
  sys.exit(__doc__)

content = ''
outsize = 0
with open(sys.argv[1], 'rb') as infile:
  content = infile.read()
with open(sys.argv[2], 'wb') as output:
  for line in content.splitlines():
    outsize += len(line) + 1
    output.write(line + '\n')

print("Done. Saved %s bytes." % (len(content)-outsize))

Отправлено через superuser.

Ответ 8

Вы можете использовать vim программно с опцией -c {команда}:

Дос в Unix:

vim file.txt -c "set ff=unix" -c ":wq"

Unix to dos:

vim file.txt -c "set ff=dos" -c ":wq"

"set ff = unix/dos" означает изменить формат файла (ff) файла на формат конца строки Unix/DOS

": wq" означает запись файла на диск и выход из редактора (что позволяет использовать команду в цикле)

Ответ 9

Чтобы конвертировать файл на месте, используйте

dos2unix <filename>

Для вывода преобразованного текста в другой файл используйте

dos2unix -n <input-file> <output-file>

Вы можете установить его на Ubuntu с помощью

sudo apt install dos2unix

или на macOS с помощью доморощенного

brew install dos2unix

Ответ 10

Супер пупер с PCRE;

Как script или замените [email protected] вашими файлами.

#!/usr/bin/env bash
perl -pi -e 's/\r\n/\n/g' -- [email protected]

Это перезапишет ваши файлы на месте!

Я рекомендую делать это только с помощью резервного копирования (контроль версий или иначе)

Ответ 11

Еще более простое awk-решение без программы:

awk -v ORS='\r\n' '1' unix.txt > dos.txt

Технически "1" - это ваша программа, b/c awk требует один, если задана опция.

UPDATE: После повторного просмотра этой страницы в первый раз за долгое время я понял, что никто еще не опубликовал внутреннее решение, так что вот один из них:

while IFS= read -r line;
do printf '%s\n' "${line%$'\r'}";
done < dos.txt > unix.txt

Ответ 12

Интересно, что в моем git - bash на окнах sed "" уже сделал трюк:

$ echo -e "abc\r" >tst.txt
$ file tst.txt
tst.txt: ASCII text, with CRLF line terminators
$ sed -i "" tst.txt
$ file tst.txt
tst.txt: ASCII text

Моя догадка заключается в том, что sed игнорирует их при чтении строк с ввода и всегда записывает окончание строк unix на выходе.

Ответ 13

Это сработало для меня

tr "\r" "\n" < sampledata.csv > sampledata2.csv 

Ответ 14

Было бы просто подумать об этом же вопросе (на стороне Windows, но в равной степени применимом к Linux). Удивительно, что никто не упомянул очень автоматизированный способ преобразования CRLF ↔ LF для текстовых файлов с использованием старой старой опции zip -ll (Info-ZIP):

zip -ll textfiles-lf.zip files-with-crlf-eol.*
unzip textfiles-lf.zip 

ПРИМЕЧАНИЕ. Это создало бы zip файл, сохраняющий исходные имена файлов, но преобразовывая окончания строки в LF. Затем unzip будет извлекать файлы как zip'ed, то есть с их исходными именами (но с LF-окончаниями), тем самым предлагая перезаписать локальные исходные файлы, если они есть.

Соответствующая выдержка из zip --help:

zip --help
...
-l   convert LF to CR LF (-ll CR LF to LF)

Ответ 15

Для Mac OSX, если у вас установлен доморощенный [http:// brew.sh/] [1]

brew install dos2unix

for csv in *.csv; do dos2unix -c mac ${csv}; done;

Убедитесь, что вы сделали копии файлов, так как эта команда будет изменять файлы на месте. Параметр -c mac делает коммутатор совместимым с osx.

Ответ 16

TIMTOWTDI!

perl -pe 's/\r\n/\n/; s/([^\n])\z/$1\n/ if eof' PCfile.txt

Основываясь на @GordonDavisson

Необходимо рассмотреть возможность [noeol]...

Ответ 17

Вы можете использовать awk. Установите разделитель записей (RS) в регулярное выражение, которое соответствует всем возможным символам новой строки или символам. И установите разделитель выходной записи (ORS) в символ новой строки в стиле unix.

awk 'BEGIN{RS="\r|\n|\r\n|\n\r";ORS="\n"}{print}' windows_or_macos.txt > unix.txt

Ответ 18

В Linux легко преобразовать ^ M (ctrl-M) в * nix newlines (^ J) с sed.

В CLI будет что-то вроде этого, в тексте будет разрыв строки. Тем не менее,\передает, что ^ J для sed:

sed 's/^M/\
/g' < ffmpeg.log > new.log

Вы получаете это, используя ^ V (ctrl-V), ^ M (ctrl-M) и\(обратная косая черта) по мере ввода:

sed 's/^V^M/\^V^J/g' < ffmpeg.log > new.log

Ответ 19

В качестве расширения для решения Jonathan Leffler Unix для DOS, чтобы безопасно конвертировать в DOS, когда вы не уверены в текущем окончании строки файла:

sed '/^M$/! s/$/^M/'

Это проверяет, что линия еще не заканчивается в CRLF перед преобразованием в CRLF.

Ответ 20

sed --expression='s/\r\n/\n/g'

Поскольку в вопросе упоминается sed, это самый простой способ использовать sed для достижения этой цели. В выражении говорится, что все возвраты каретки и перевод строки заменяются только переводом строки. Это то, что вам нужно, когда вы переходите с Windows на Unix. Я проверил, что это работает.

Ответ 21

Я сделал скрипт, основанный на принятом ответе, чтобы вы могли конвертировать его напрямую, без необходимости в дополнительном файле, а затем удалять и переименовывать.

convert-crlf-to-lf() {
    file="$1"
    tr -d '\015' <"$file" >"$file"2
    rm -rf "$file"
    mv "$file"2 "$file"
}

Просто убедитесь, что если у вас есть файл типа "file1.txt", которого "file1.txt2" не существует, или он будет перезаписан, я использую его как временное место для хранения файла.

Ответ 22

Я пробовал sed 's/^ M $//' file.txt на OSX, а также несколько других методов (http://www.thingy-ma-jig.co.uk/blog/25-11-2010/fixing-dos-line-endings или http://hintsforums.macworld.com/archive/index.php/t-125.html). Ничего не работало, файл остался без изменений (для воспроизведения ^ М) потребовалось ввести бит-в-В. В конце я использовал TextWrangler. Это не строго командная строка, но она работает, и она не жалуется.

Ответ 23

Есть много ответов awk/sed/etc, так как дополнение (поскольку это один из лучших результатов поиска для этой проблемы):

У вас может не быть dos2unix, но у вас есть iconv?

iconv -f UTF-16LE -t UTF-8 [filename.txt]
-f from format type
-t to format type

Или все файлы в каталоге:

find . -name "*.sql" -exec iconv -f UTF-16LE -t UTF-8 {} -o ./{} \;

Выполняет ту же самую команду для всех файлов .sql в текущей папке. -o - это выходной каталог, поэтому вы можете заменить его текущими файлами или, по соображениям безопасности/резервного копирования, выводить в отдельный каталог.