Как преобразовать новую строку DOS/Windows (CRLF) в новую строку Unix (LF) в сценарии Bash?
Как я могу программно (то есть, не используя vi
) конвертировать DOS/Windows новые строки в Unix?
dos2unix
а также unix2dos
Команды недоступны в определенных системах. Как я могу подражать этим с помощью команд, таких как sed
/awk
/tr
?
25 ответов
Ты можешь использовать tr
конвертировать из DOS в Unix; однако вы можете сделать это безопасно только в том случае, если CR появляется в вашем файле только как первый байт пары байтов CRLF. Обычно это так. Затем вы используете:
tr -d '\015' <DOS-file >UNIX-file
Обратите внимание, что имя DOS-file
отличается от названия UNIX-file
; если вы попытаетесь использовать одно и то же имя дважды, у вас не будет данных в файле.
Вы не можете сделать это наоборот (со стандартным 'tr').
Если вы знаете, как ввести возврат каретки в сценарий (control-V, control-M для ввода control-M), то:
sed 's/^M$//' # DOS to Unix
sed 's/$/^M/' # Unix to DOS
где '^M' является символом control-M. Вы также можете использовать bash
Механизм цитирования ANSI-C для указания возврата каретки:
sed $'s/\r$//' # DOS to Unix
sed $'s/$/\r/' # Unix to DOS
Однако, если вам придется делать это очень часто (более одного раза, грубо говоря), гораздо разумнее установить конверсионные программы (например, dos2unix
а также unix2dos
или возможно dtou
а также utod
) и использовать их.
Вы можете использовать vim программно с опцией -c {команда}:
Дос в Unix:
vim file.txt -c "set ff=unix" -c ":wq"
Unix to dos:
vim file.txt -c "set ff=dos" -c ":wq"
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
,
Чтобы конвертировать файл на месте, сделайте
dos2unix <filename>
Для вывода преобразованного текста в другой файл выполните
dos2unix -n <input-file> <output-file>
Он уже установлен в Ubuntu и доступен на доморощенном с brew install dos2unix
Я знаю, что вопрос явно требует альтернатив этой утилите, но это первый результат поиска в Google по запросу "конвертировать dos в окончание строки Unix".
Делать это с POSIX сложно:
POSIX Sed не поддерживает
\r
или же\15
, Даже если это так, вариант на месте-i
это не POSIXPOSIX Awk поддерживает
\r
а также\15
, Тем не менее-i inplace
вариант не POSIXd2u и 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
Используя AWK, вы можете сделать:
awk '{ sub("\r$", ""); print }' dos.txt > unix.txt
Используя Perl вы можете сделать:
perl -pe 's/\r$//' < dos.txt > unix.txt
Эту проблему можно решить стандартными инструментами, но для неосторожных достаточно ловушек, поэтому я рекомендую вам установить flip
команда, которая была написана более 20 лет назад Рахулом Дези, автором zoo
, Он отлично справляется с конвертированием форматов файлов, избегая, например, случайного уничтожения двоичных файлов, что будет слишком легко, если вы просто мчитесь вокруг изменения каждого CRLF, который вы видите...
Если у вас нет доступа к 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))
Кросс-пост от суперпользователя.
Опубликованные на данный момент решения касаются только части проблемы, превращая DRL /Windows CRLF в LIX Unix; часть, которую они пропускают, состоит в том, что DOS использует CRLF в качестве разделителя строк, в то время как Unix использует LF в качестве ограничителя строки. Разница в том, что файл DOS (обычно) не будет иметь ничего после последней строки в файле, в то время как Unix будет. Чтобы правильно выполнить преобразование, вам нужно добавить этот окончательный LF (если только файл не имеет нулевой длины, то есть не содержит строк). Мое любимое заклинание для этого (с небольшой добавленной логикой для обработки файлов в стиле Mac в стиле CR, а не для файлов, которые уже находятся в формате 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 версию файла на стандартный вывод. Если вы хотите заменить файл на Unixified версию, добавьте perl's -i
флаг.
Супер пупер легко с PCRE;
Как скрипт или заменить $@
с вашими файлами.
#!/usr/bin/env bash
perl -pi -e 's/\r\n/\n/g' -- $@
Это заменит ваши файлы на месте!
Я рекомендую делать это только с резервной копией (контроль версий или другое)
Еще более простое решение awk без программы:
awk -v ORS='\r\n' '1' unix.txt > dos.txt
Технически, "1" - это ваша программа, b/c awk требует ее при данной опции.
ОБНОВЛЕНИЕ: После повторного посещения этой страницы впервые за долгое время я понял, что никто еще не опубликовал внутреннее решение, поэтому вот одно:
while IFS= read -r line;
do printf '%s\n' "${line%$'\r'}";
done < dos.txt > unix.txt
Интересно в моем git-bash на windows 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 на выходе.
Просто задумался над тем же вопросом (на стороне 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)
Для Mac OSX, если у вас установлен homebrew [ http://brew.sh/%5D%5B1%5D
brew install dos2unix
for csv in *.csv; do dos2unix -c mac ${csv}; done;
Убедитесь, что вы сделали копии файлов, так как эта команда изменит файлы на месте. Опция -c mac делает этот переключатель совместимым с osx.
Просто дополняя отличный ответ @Jonathan Leffler, если у вас есть файл со смешанными окончаниями строк (LF и CRLF) и вам нужно нормализовать до CRLF (DOS), последовательно используйте следующие команды...
# DOS to Unix
sed -i $'s/\r$//' "<YOUR_FILE>"
# Unix to DOS (normalized)
sed -i $'s/$/\r/' "<YOUR_FILE>"
ПРИМЕЧАНИЕ. Если у вас есть файл со смешанными окончаниями строк (LF и CRLF), одна только вторая команда выше вызовет беспорядок.
Если вам нужно преобразовать в LF (Unix), будет достаточно только первой команды...
# DOS to Unix
sed -i $'s/\r$//' "<YOUR_FILE>"
Спасибо!
[Ссылка (ы).: https://stackoverflow.com/a/3777853/3223785 ]
sed --expression='s/\r\n/\n/g'
Поскольку в вопросе упоминается sed, это самый простой способ использовать sed для достижения этой цели. В выражении говорится, что все возвраты каретки и перевод строки заменяются только переводом строки. Это то, что вам нужно, когда вы переходите с Windows на Unix. Я проверил, что это работает.
Это сработало для меня
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]
...
Вы можете использовать awk. Установить разделитель записей (RS
) к регулярному выражению, которое соответствует всем возможным символам новой строки или символам. И установить разделитель выходной записи (ORS
) символу новой строки в стиле Unix.
awk 'BEGIN{RS="\r|\n|\r\n|\n\r";ORS="\n"}{print}' windows_or_macos.txt > unix.txt
В Linux легко конвертировать ^M (ctrl-M) в *nix переводы строк (^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
Я сделал скрипт, основанный на принятом ответе, чтобы вы могли конвертировать его напрямую, без необходимости в дополнительном файле, а затем удалять и переименовывать.
convert-crlf-to-lf() {
file="$1"
tr -d '\015' <"$file" >"$file"2
rm -rf "$file"
mv "$file"2 "$file"
}
Просто убедитесь, что если у вас есть файл типа "file1.txt", которого "file1.txt2" не существует, или он будет перезаписан, я использую его как временное место для хранения файла.
В качестве расширения решения Jonathan Leffler для Unix to DOS можно безопасно конвертировать в DOS, если вы не уверены в конце строки файла:
sed '/^M$/! s/$/^M/'
Это проверяет, что строка еще не заканчивается CRLF перед преобразованием в CRLF.
В bash 4.2 и новее вы можете использовать что-то вроде этого для удаления завершающего CR, который использует только встроенные модули bash:
if [[ "${str: -1}" == $'\r' ]]; then
str="${str:: -1}"
fi
Я попробовал файл sed 's/^M$//' для 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). Ничего не сработало, файл остался без изменений (кстати, Ctrl-v Enter был необходим для воспроизведения ^M). В конце концов я использовал 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 является выходным каталогом, поэтому вы можете заменить его текущими файлами или, в целях безопасности / резервного копирования, вывести в отдельный каталог.