如何在Bash脚本中将DOS / Windows换行符(CRLF)转换为Unix换行符(LF)?

时间:2010-04-10 15:03:34

标签: linux windows bash unix newline

如何以编程方式(即不使用vi)将DOS / Windows换行符转换为Unix?

dos2unixunix2dos命令在某些系统上不可用。如何使用sed / awk / tr等命令模拟这些?

24 个答案:

答案 0 :(得分:299)

您可以使用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 Quoting机制指定回车符:

sed $'s/\r$//'     # DOS to Unix
sed $'s/$/\r/'     # Unix to DOS

但是,如果您不得不经常这样做(不止一次,粗略地说),安装转换程序(例如dos2unixunix2dos则更为明智,或者dtouutod)并使用它们。

答案 1 :(得分:56)

tr -d "\r" < file

使用sed查看示例here

# 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

答案 2 :(得分:36)

使用POSIX执行此操作非常棘手:

  • POSIX Sed不支持\r\15。即使它确实如此,到位 选项-i不是POSIX

  • POSIX Awk支持\r\15,但是-i inplace选项 不是POSIX

  • d2u dos2unix 不是POSIX utilities,但 ex

  • POSIX ex不支持\r\15\n\12

删除回车:

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

添加回车符:

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

答案 3 :(得分:20)

使用AWK可以:

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

使用Perl,您可以:

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

答案 4 :(得分:19)

这个问题可以通过标准工具解决,但是对于粗心大意有足够多的陷阱,我建议你安装flip命令,这是20多年前由{{{{{{{{ 1}}。 它在转换文件格式方面表现非常出色,例如,避免了二进制文件的无意破坏,如果你只是在改变你看到的每个CRLF,那就太容易了......

答案 5 :(得分:14)

到目前为止发布的解决方案只处理部分问题,将DOS / Windows的CRLF转换为Unix的LF;他们缺少的部分是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版本发送到stdout。如果要使用Unixified版本替换该文件,请添加perl的-i标志。

答案 6 :(得分:13)

如果您无权访问 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交叉发布。

答案 7 :(得分:10)

您可以通过-c {command}选项以编程方式使用vim:

使用Unix:

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

要执行的Unix:

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

“设置ff = unix / dos”表示将文件的文件格式(ff)更改为Unix / DOS行尾格式

“:wq”表示将文件写入磁盘并退出编辑器(允许循环使用该命令)

答案 8 :(得分:8)

要就地转换文件,请

dos2unix <filename>

要将转换后的文本输出到其他文件,请执行

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

它已经安装在Ubuntu上,并且可以通过brew install dos2unix在自制软件上使用


我知道这个问题明确要求使用该实用程序的替代方法,但这是Google第一个将“将dos转换为unix行尾”的搜索结果。

答案 9 :(得分:8)

使用PCRE轻松实现超级便携;

作为脚本,或将$@替换为您的文件。

#!/usr/bin/env bash
perl -pi -e 's/\r\n/\n/g' -- $@
  

这将覆盖您的文件!

     

我建议只使用备份(版本控制或其他方式)

答案 10 :(得分:6)

一个更简单的awk解决方案,无需程序:

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

技术上&#39; 1&#39;是你的程序,b / c awk在给定选项时需要一个。

<强>更新: 在很长一段时间内第一次重新访问这个页面后,我意识到还没有人发布内部解决方案,所以这里有一个:

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

答案 11 :(得分:4)

有趣的是,在我的git-bash on 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行结尾。

答案 12 :(得分:3)

这对我有用

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

答案 13 :(得分:3)

只是想思考同样的问题(在Windows端,但同样适用于Linux。) 令人惊讶的是,没有人提到使用良好的旧zip -ll选项(Info-ZIP)对文本文件进行CRLF&lt; - &gt; LF转换的非常自动化的方式:

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

注意:这将创建一个zip文件,保留原始文件名,但将行结尾转换为LF。然后unzip会将文件解压缩为zip文件,即使用原始名称(但使用LF结尾),从而提示覆盖本地原始文件(如果有)。

zip --help的相关摘录:

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

答案 14 :(得分:2)

TIMTOWTDI!

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

基于@GordonDavisson

必须考虑[noeol] ...

的可能性

答案 15 :(得分:1)

你可以使用awk。将记录分隔符(RS)设置为与所有可能的换行符或字符匹配的正则表达式。并将输出记录分隔符(ORS)设置为unix样式的换行符。

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

答案 16 :(得分:1)

在Linux上,很容易通过sed将^ M(ctrl-M)转换为* nix换行符(^ J)。

在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

答案 17 :(得分:1)

对于Mac osx,如果您安装了自制软件[http://brew.sh/][1]

brew install dos2unix

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

确保您已制作文件的副本,因为此命令将修改文件。 -c mac选项使交换机与osx兼容。

答案 18 :(得分:0)

作为Jonathan Leffler的Unix到DOS解决方案的扩展,当你不确定文件的当前行结尾时安全地转换为DOS:

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

这会在转换为CRLF之前检查该行是否已在CRLF中结束。

答案 19 :(得分:0)

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

由于问题提到sed,这是使用sed实现此目的的最直接方法。表达式说的是仅用换行替换所有回车和换行。从Windows到Unix,这就是您所需要的。我验证了它的作用。

答案 20 :(得分:0)

我根据接受的答案制作了一个脚本,因此您可以直接将其转换,而无需最后添加其他文件,之后再删除并重命名。

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

只要确保您没有“ file1.txt2”之类的文件(例如“ file1.txt”),否则该文件将被覆盖,我将其用作存储文件的临时位置。

答案 21 :(得分:0)

在bash 4.2及更高版本中,您可以使用类似这样的方法剥离尾随CR,该CR仅使用bash内置功能:

if [[ "${str: -1}" == $'\r' ]]; then
    str="${str:: -1}"
fi

答案 22 :(得分:-3)

我试过了 sed's / ^ M $ //'file.txt 在OSX上以及其他几种方法(http://www.thingy-ma-jig.co.uk/blog/25-11-2010/fixing-dos-line-endingshttp://hintsforums.macworld.com/archive/index.php/t-125.html)。没有工作,文件保持不变(btw Ctrl-v Enter需要重现^ M)。最后我使用了TextWrangler。它不是严格的命令行,但它的工作原理并没有抱怨。

答案 23 :(得分:-5)

有很多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是输出目录,因此您可以将其替换为当前文件,或者出于安全/备份原因,输出到单独的目录。