Как я могу программным способом (т.е. не использовать vi
) конвертировать строки DOS/Windows в Unix?
Команды dos2unix
и unix2dos
недоступны в некоторых системах. Как я могу имитировать их с помощью команд типа sed
/awk
/tr
?
Вы можете использовать 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
) и используйте их.
tr -d '\015' <DOS-file >UNIX-file
где DOS-file
== UNIX-file
просто приводит к пустому файлу. Выходной файл, к сожалению, должен быть другим файлом.
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
.
\r
: tr "\r" "\n" < infile > outfile
-d
используется чаще и не поможет в ситуации "only \r
".
Выполнение этого с помощью 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
tr
поддерживает \r
. Таким образом, вы также можете использовать printf '%s\n' '%!tr -d "\r"' x | ex file
(хотя и предоставленный, он удаляется \r
даже если он не предшествует \n
). Кроме того, опция -b
для ex
не указана в POSIX.
Эта проблема может быть решена с помощью стандартных инструментов, но для неосторожных есть достаточно много ловушек, которые я рекомендую вам установить flip
, который был написан более 20 лет назад Рахулом Деси, автором zoo
.
Он отлично работает, конвертируя форматы файлов, в то время как, например, избегая случайного уничтожения двоичных файлов, что слишком легко, если вы просто участвуете в изменении каждого CRLF, который вы видите...
Используя AWK, вы можете:
awk '{ sub("\r$", ""); print }' dos.txt > unix.txt
Используя Perl, вы можете:
perl -pe 's/\r$//' < dos.txt > unix.txt
awk
.
Решения, опубликованные до сих пор, касаются только части проблемы, конвертируя 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
.
Если у вас нет доступа к 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.
dos2unix
по умолчанию конвертирует все входные файлы. Ваше использование подразумевает параметр -n
. А настоящий dos2unix
- это фильтр, который читает из stdin и записывает в stdout, если файлы не передаются.
dos2unix
реальны? Это в стандарте POSIX?
Супер пупер с PCRE;
Как script или замените $@
вашими файлами.
#!/usr/bin/env bash
perl -pi -e 's/\r\n/\n/g' -- $@
Это перезапишет ваши файлы на месте!
Я рекомендую делать это только с помощью резервного копирования (контроль версий или иначе)
--
. Я выбрал это решение, потому что это легко понять и адаптировать для меня. К вашему сведению, это то, что делают переключатели: -p
предполагают цикл «во время ввода», -i
редактируют входной файл на месте, -e
выполняют следующую команду
Еще более простое 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
awk -v RS='\r\n' '1' dos.txt > unix.txt
Чтобы преобразовать файл на место, выполните
dos2unix <filename>
Для вывода преобразованного текста в другой файл выполните
dos2unix -n <input-file> <output-file>
Он уже установлен на Ubuntu и доступен на homebrew с brew install dos2unix
Я знаю, что вопрос явно запрашивает альтернативы этой утилите, но это первый результат поиска google для "convert dos to unix line endings".
Интересно, что в моем 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 на выходе.
Вы можете использовать vim программно с опцией -c {команда}:
Дос для Unix:
vim file.txt -c "set ff=unix" -c ":wq"
Unix для dos:
vim file.txt -c "set ff=dos" -c ":wq"
vi
будет знать, что означает :wq
. Для тех, кто не использует 3 символа, это означает 1) открытая область команд vi, 2) запись и 3) выход.
Это сработало для меня
tr "\r" "\n" < sampledata.csv > sampledata2.csv
TIMTOWTDI!
perl -pe 's/\r\n/\n/; s/([^\n])\z/$1\n/ if eof' PCfile.txt
Основываясь на @GordonDavisson
Необходимо рассмотреть возможность [noeol]
...
Было бы просто подумать об этом же вопросе (на стороне 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)
Вы можете использовать awk. Установите разделитель записей (RS
) в регулярное выражение, которое соответствует всем возможным символам новой строки или символам. И установите разделитель выходной записи (ORS
) в символ новой строки в стиле unix.
awk 'BEGIN{RS="\r|\n|\r\n|\n\r";ORS="\n"}{print}' windows_or_macos.txt > unix.txt
git diff
показывает ^ M, отредактировано в vim)
Для Mac OSX, если у вас установлен доморощенный [http:// brew.sh/] [1]
brew install dos2unix
for csv in *.csv; do dos2unix -c mac ${csv}; done;
Убедитесь, что вы сделали копии файлов, так как эта команда будет изменять файлы на месте. Параметр -c mac делает коммутатор совместимым с osx.
dos2unix
оказался довольно удобным!
sed --expression='s/\r\n/\n/g'
Поскольку в вопросе упоминается sed, это самый простой способ использовать sed для достижения этой цели. В выражении говорится, что все возвраты каретки и перевод строки заменяются только переводом строки. Это то, что вам нужно, когда вы переходите с Windows на Unix. Я проверил, что это работает.
В 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
В качестве расширения для решения Jonathan Leffler Unix для DOS, чтобы безопасно конвертировать в DOS, когда вы не уверены в текущем окончании строки файла:
sed '/^M$/! s/$/^M/'
Это проверяет, что линия еще не заканчивается в CRLF перед преобразованием в CRLF.
Я пробовал 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. Это не строго командная строка, но она работает, и она не жалуется.
Есть много ответов 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 - это выходной каталог, поэтому вы можете заменить его текущими файлами или, по соображениям безопасности/резервного копирования, выводить в отдельный каталог.
dos2unix
с помощью вашего менеджера пакетов, это действительно намного проще и существует на большинстве платформ.