How to convert DOS/Windows newline (CRLF) to Unix newline (LF) in a Bash script?
如何以编程方式(即,不使用
您可以使用
1 | tr -d '\015' <DOS-file >UNIX-file |
请注意,名称
你不能反过来做(使用标准'tr')。
如果你知道如何将回车输入脚本(control-V,control-M进入control-M),那么:
1 2 | sed 's/^M$//' # DOS to Unix sed 's/$/^M/' # Unix to DOS |
其中'^ M'是控制-M字符。您还可以使用
1 2 3 4 | sed $'s/ $//' # DOS to Unix sed $'s/$/ /' # Unix to DOS |
但是,如果您不得不经常这样做(不止一次,粗略地说),安装转换程序更为明智(例如
1 2 | tr -d" " < file |
看一下使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # 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 \\ `/" # command line under ksh sed 's/$'"/`echo \\ `/" # command line under bash sed"s/$/`echo \\ `/" # command line under zsh sed 's/$/ /' # gsed 3.02.80 or higher |
使用
使用POSIX执行此操作非常棘手:
-
POSIX Sed不支持
或
\15 。即使它确实如此,到位
选项-i 不是POSIX -
POSIX Awk支持
和
\15 ,但是-i inplace 选项
不是POSIX -
d2u和dos2unix不是POSIX实用程序,但ex是
-
POSIX ex不支持
,
\15 , 或
\12
要删除回车:
1 2 | ex -bsc '%!awk"{sub(/ /,"")}1"' -cx file |
要添加回车:
1 2 | ex -bsc '%!awk"{sub(/$/," ")}1"' -cx file |
使用AWK你可以做到:
1 2 | awk '{ sub(" $",""); print }' dos.txt > unix.txt |
使用Perl你可以做到:
1 2 | perl -pe 's/ $//' < dos.txt > unix.txt |
这个问题可以通过标准工具解决,但是对于粗心大意有足够多的陷阱,我建议你安装
它在转换文件格式方面表现非常出色,例如,避免了二进制文件的无意破坏,如果你只是在改变你看到的每个CRLF,那就太容易了...
您可以使用选项-c {command}以编程方式使用vim:
Dos到Unix:
1 | vim file.txt -c"set ff=unix" -c":wq" |
Unix到dos:
1 | vim file.txt -c"set ff=dos" -c":wq" |
"set ff = unix / dos"表示将文件的fileformat(ff)更改为Unix / DOS行格式
":wq"表示将文件写入磁盘并退出编辑器(允许在循环中使用该命令)
到目前为止发布的解决方案只处理部分问题,将DOS / Windows的CRLF转换为Unix的LF;他们缺少的部分是DOS使用CRLF作为行分隔符,而Unix使用LF作为行终止符。区别在于DOS文件(通常)在文件的最后一行之后没有任何内容,而Unix则会。要正确进行转换,您需要添加最终的LF(除非文件为零长度,即根本没有行)。我最喜欢的咒语(有一点点添加逻辑来处理Mac风格的CR分离文件,而不是已经采用unix格式的最小文件)有点perl:
1 2 3 4 5 6 | perl -pe 'if ( s/ ?/ /g ) { $f=1 }; if ( $f || ! $m ) { s/([^ ])\z/$1 / }; $m=1' PCfile.txt |
请注意,这会将文件的Unixified版本发送到stdout。如果要使用Unixified版本替换该文件,请添加perl的
如果您无权访问dos2unix,但可以阅读此页面,那么您可以从此处复制/粘贴dos2unix.py。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/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 + ' ') print("Done. Saved %s bytes." % (len(content)-outsize)) |
从超级用户交叉发布。
要在适当的位置转换文件
1 | dos2unix <filename> |
要将转换后的文本输出到其他文件,请使用
1 | dos2unix -n <input-file> <output-file> |
你可以在Ubuntu上安装它
1 | sudo apt install dos2unix |
或者使用自制软件在macOS上
1 | brew install dos2unix |
使用PCRE轻松实现超级便携;
作为脚本,或用文件替换
1 2 3 4 5 | #!/usr/bin/env bash perl -pi -e 's/ / /g' -- $@ |
This will overwrite your files in place!
I recommend only doing this with a backup (version control or otherwise)
一个更简单的awk解决方案,没有一个程序:
1 2 3 | awk -v ORS=' ' '1' unix.txt > dos.txt |
技术上'1'是你的程序,b / c awk在给定选项时需要一个。
更新:
在很长一段时间内第一次重新访问这个页面后,我意识到还没有人发布内部解决方案,所以这里有一个:
1 2 3 4 5 | while IFS= read -r line; do printf '%s '"${line%$' '}"; done < dos.txt > unix.txt |
有趣的是,我在windows
1 2 3 4 5 6 7 | $ echo -e"abc ">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行结尾。
这对我有用
1 2 3 | tr" "" " < sampledata.csv > sampledata2.csv |
只是想思考同样的问题(在Windows端,但同样适用于Linux。)
令人惊讶的是,没有人提到使用旧的
1 2 | zip -ll textfiles-lf.zip files-with-crlf-eol.* unzip textfiles-lf.zip |
注意:这将创建一个zip文件,保留原始文件名,但将行结尾转换为LF。然后
1 2 3 | zip --help ... -l convert LF to CR LF (-ll CR LF to LF) |
对于Mac osx,如果你已经安装了自制软件[http://brew.sh/][1]
1 2 3 | brew install dos2unix for csv in *.csv; do dos2unix -c mac ${csv}; done; |
确保已创建文件的副本,因为此命令将修改文件。
-c mac选项使交换机与osx兼容。
在Linux上,使用sed将^ M(ctrl-M)转换为* nix换行符(^ J)很容易。
在CLI上它会是这样的,文本中实际上会有换行符。然而,将^ J传递给sed:
1 2 | sed 's/^M/\ /g' < ffmpeg.log > new.log |
您可以在键入时使用^ V(ctrl-V),^ M(ctrl-M)和(反斜杠)来获得:
1 | sed 's/^V^M/\^V^J/g' < ffmpeg.log > new.log |
TIMTOWTDI!
1 2 3 4 5 6 | perl -pe 's/ / /; s/([^ ])\z/$1 / if eof' PCfile.txt |
基于@GordonDavisson
必须考虑
你可以使用awk。将记录分隔符(
1 2 3 4 5 6 7 8 | awk 'BEGIN{RS=" | | | ";ORS=" "}{print}' windows_or_macos.txt > unix.txt |
我根据接受的答案制作了一个脚本,这样你就可以直接转换它,而不需要最后一个额外的文件,然后删除和重命名。
1 2 3 4 5 6 | 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到DOS解决方案的扩展,当您不确定文件的当前行结尾时安全地转换为DOS:
1 | sed '/^M$/! s/$/^M/' |
这会在转换为CRLF之前检查该行是否已在CRLF中结束。
1 2 3 4 | sed --expression='s/ / /g' |
由于问题提到了sed,这是使用sed实现这一目标的最直接的方法。表达式所说的是仅使用换行替换所有回车和换行。这是从Windows到Unix时所需要的。我确认它有效。
我试过了
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)。没有工作,文件保持不变(btw Ctrl-v Enter需要重现^ M)。最后我使用了TextWrangler。它不是严格的命令行,但它的工作原理并没有抱怨。
有很多awk / sed / etc答案作为补充(因为这是此问题的最佳搜索结果之一):
你可能没有dos2unix,但你有iconv吗?
1 2 3 | iconv -f UTF-16LE -t UTF-8 [filename.txt] -f from format type -t to format type |
或者目录中的所有文件:
1 | find . -name"*.sql" -exec iconv -f UTF-16LE -t UTF-8 {} -o ./{} \; |
这将在当前文件夹中的所有.sql文件上运行相同的命令。 -o是输出目录,因此您可以将其替换为当前文件,或者出于安全/备份原因,输出到单独的目录。