2010-04-10 95 views
226

如何以编程方式(即不使用vi)将DOS/Windows换行符转换为Unix?如何在Bash脚本中将DOS/Windows换行符(CRLF)转换为Unix换行符( n)?

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

+0

如果你可以编译到目标系统上,你可以试试https://github.com/mdolidon/endlines;它的制作非常便携。 – 2014-09-03 10:17:32

+5

通常,只需使用软件包管理器来安装'dos2unix',它确实简单得多,而且在大多数平台上都存在。 – 2015-10-20 20:15:43

回答

15

使用AWK,你可以这样做:

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

使用Perl,你可以这样做:

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

一个不错的_portable_ awk解决方案。 – mklement0 2015-02-28 05:29:08

243

您可以使用tr从DOS到Unix的转换;但是,如果CR仅在CRLF字节对的第一个字节中出现在文件中,则只能安全地执行此操作。这通常是这种情况。然后,可以使用:

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

注意名称DOS-file是从名字UNIX-file不同;如果您尝试使用两次相同的名称,则最终会在文件中没有数据。

你不能这样做(使用标准'tr')。

如果你知道如何进入回车到一个脚本(控制-V控制-M进入控制-M),则:

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

其中 '^ M' 是控制-M字符。您也可以使用bashANSI-C Quoting机制,指定回车:

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

但是,如果你将不得不这样做经常(一次以上,粗略地讲),这是更为明智的安装转换程序(例如dos2unixunix2dos,或者可能是dtouutod)并使用它们。

+3

使用'tr -d'\ 015' UNIX-file'其中'DOS-file' =='UNIX-file'只是产生一个空文件。不幸的是,输出文件必须是不同的文件。 – 2013-11-15 01:50:02

+2

@ButtleButkus:恩,是的。这就是为什么我使用了两个不同的名字。如果您在程序全部读取之前切换输入文件,就如同您使用相同名称两次时一样,最终会得到一个空文件。这是类Unix系统中的统一行为。它需要特殊的代码才能安全地处理输入文件的覆盖。按照说明,你会没事的。 – 2013-11-15 01:56:35

+0

我似乎记得文件中的搜索替换功能。 – 2013-11-15 02:08:22

46
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

+9

我使用了一个变体,因为我的文件只有'\ r':'tr“\ r”“\ n”< infile > outfile' – 2010-11-19 00:29:01

+0

@MattTodd你可以发布这个答案吗? '-d'更频繁地被使用,并且在“只有'\ r'”情况下不起作用。 – n611x007 2013-10-14 15:20:52

+2

请注意,建议'\ r'映射为'\ n'具有双重间隔文件的效果;每个在DOS结尾的单个CRLF行在Unix中变成'\ n \ n'。 – 2014-04-30 13:58:31

14

到目前为止发布的解决方案只处理部分问题,将DOS/Windows的CRLF转换为Unix的LF;他们缺少的部分是DOS使用CRLF作为行分隔符,而Unix使用LF作为行终止符。区别在于DOS文件(通常)在文件的最后一行之后没有任何内容,而Unix将会有。为了正确地进行转换,你需要添加最后的LF(除非文件是零长度,即根本没有行)。我最喜欢这个咒语(一点点添加逻辑来处理的Mac风格的CR-分隔的文件,而不是骚扰文件that're已经是UNIX格式)是位的Perl:

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

注意,这将将stdout文件的Unix化版本。如果您想用Unix化版本替换文件,请添加perl的-i标志。

+0

RIP我的数据文件。在某处出错xD – 2016-01-21 10:53:24

+0

@LudovicZenohateLagouardette它是一个纯文本文件(即csv或tab-demited文本)还是其他?如果它是以某种数据库形式存在的,那么操纵它就好像它是文本一样,这很可能会破坏它的内部结构。 – 2016-01-23 20:53:26

+0

明文csv,但我认为enconding很奇怪。我认为它因此而搞砸了。不过别担心。我总是收集备份,这甚至不是真正的数据集,只有1GB。真实是26GB。 – 2016-01-24 08:02:44

18

这个问题可以用标准工具来解决,但是对于粗心大意的我有足够多的陷阱,我建议你安装flip命令,该命令是由作者zoo的作者Rahul Dhesi在20年前编写的。 它做了出色的工作转换文件格式,同时,例如,避免二进制文件的疏忽造成的破坏,这是一个有点太容易了,如果你只是比赛围绕改变每次你看到CRLF ......

+0

任何方式以流媒体的方式做到这一点,而无需修改原始文件? – augurar 2013-12-07 22:08:18

+0

@augurar你可能会检查“类似的软件包”https://packages.debian.org/wheezy/flip – n611x007 2014-08-19 11:12:03

9

如果您没有访问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

+0

这个用法很具误导性。真正的'dos2unix'默认转换* all *输入文件。您的使用意味着'-n'参数。真正的'dos2unix'是一个从stdin读取的过滤器,如果没有给出文件,则写入stdout。 – jfs 2015-07-06 11:32:13

+1

@ J.F.Sebastian哪个'dos2unix'工具是真实的?它是否符合POSIX标准? – 2015-07-06 15:39:08

+0

你的意思是哪个'dos2unix'?我的意思是:'sudo apt-get install dos2unix' – jfs 2015-07-06 15:42:15

34

与POSIX这样做是棘手:

  • POSIX Sed不支持\r\15。即使这样做了,在地方 选项-i没有POSIX

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

  • D2UDOS2UNIX的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 
+2

看起来像[POSIX'tr'支持'\ r'。](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tr.html#tag_20_132_13)所以你也可以使用'printf'%s \ n''%!tr -d“\ r”'x | ex文件“(尽管已被授予,即使不是在\ n之前,也删除了\ r)。另外,'ex'的'-b'选项不是由POSIX指定的。 – Wildcard 2017-02-28 01:50:06

0

对于Mac OSX,如果你有自制软件安装[http://brew.sh/][1]

brew install dos2unix 

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

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

+0

'dos2unix'竟然相当方便! – HelloGoodbye 2014-08-21 15:12:11

+0

这个答案真的不是原始海报的问题。 – hlin117 2015-02-07 17:43:10

+1

OS X用户不应该使用'-c mac',它用于转换pre-OS X''CR'-只换行符。您只想将该模式用于Mac OS 9或之前的文件。 – askewchan 2016-04-14 13:20:05

6

一个更简单的解决方案awk的W/O的程序:

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 
+0

这很方便,但要清楚:它将转换Unix - > Windows/DOS,这是OP要求的_opposite方向。 – mklement0 2015-02-28 06:01:54

+5

它是故意完成的,作为作者的练习。 _eyerolls_ 'awk -v RS ='\ r \ n''1'dos.txt> unix.txt' – nawK 2015-03-01 04:14:22

+0

非常棒(并且对您的教学技巧非常感谢)。 “ – mklement0 2015-03-01 04:35:30

3

这为我工作

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

这会将每个_single_ DOS-newline转换成_two_ UNIX-newlines。 – Melebius 2015-08-04 06:11:35

5

超级duper容易与PCRE;

作为脚本,或用您的文件替换[email protected]

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

这将覆盖到位您的文件!

我建议只这样做有备份(版本控制或其他方式)

+0

谢谢!这工作,虽然我正在写文件名并没有'--'。 我选择了这个解决方案,因为它很容易理解和适应我。 仅供参考,这就是交换机所做的: '-p'假设一个“while input input”循环,'-i'编辑输入文件到位,'-e'执行以下命令 – Rolf 2017-10-11 12:21:07

+0

严格地说,PCRE是Perl的重新实现正则表达式引擎,而不是Perl的正则表达式引擎。他们都有这种能力,尽管也有不同之处,尽管这个名字有其含义。 – tripleee 2017-10-27 08:24:49

1

TIMTOWTDI!

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

基于@GordonDavisson

一个必须考虑的[noeol]可能性...

1

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

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

这是一个为我工作的(MacOS,'git diff'显示^ M,在vim中编辑) – Dorian 2017-03-01 09:17:44

0

进行了扩展,乔纳森·莱弗勒的Unix到DOS的解决方案,安全地转换为DOS,当你不能确定该文件的当前行结尾的:

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

这将检查该行已不在转换为CRLF之前在CRLF中结束。

0

方才去思考同样的问题 令人惊奇的是没有人提到这样做CRLF <的非常自动化的方式(在Windows的一面,但同样适用于Linux操作系统。) - 用好老zip -ll选项的文本文件> LF转换(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) 
3

有趣的是在我的混帐的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行尾。

-3

有很多的awk/SED /等答案,从而补充(因为这是这个问题上的搜索结果中的一个):

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

+1

这试图实现从UTF-16LE到UTF-8的编码转换,但它不会触及行结尾。它与被问到的问题无关。 – Palec 2017-10-13 13:36:38

+0

我的不好。我会验证这一点,但是,我刚刚使用了THAT DAY解决了我的文件不能运行的问题,因为它们是Windows格式的。 – 2017-10-14 17:34:16

+1

这也是一个常见问题,但不是OP询问的问题(并且比CRLF问题少得多)。 – tripleee 2017-10-27 08:22:32