如何将DOS/Windows换行符(CRLF)转换为Unix换行符(LF)

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

dos2unixunix2dos命令在某些系统上不可用。< br / > 如何用sedawktr等命令模拟它们?< / p >

566374 次浏览

使用AWK你可以做到:

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

使用Perl你可以做到:

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

你可以使用tr从DOS转换到Unix;但是,只有当CR仅作为CRLF字节对的第一个字节出现在文件中时,才能安全地执行此操作。通常情况都是这样。然后使用:

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

注意,名称DOS-file不同于名称UNIX-file;如果您尝试使用相同的名称两次,您将在文件中没有数据。

你不能反过来做(用标准的'tr')。

如果你知道如何在脚本中输入回车符(- vcontrol-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

然而,如果你必须经常这样做(粗略地说,不止一次),安装转换程序(例如dos2unixunix2dos,或者dtouutod)并使用它们是更明智的。

如果你需要处理整个目录和子目录,你可以使用zip:

zip -r -ll zipfile.zip somedir/
unzip zipfile.zip

这将创建一个zip归档文件,行结束符从CRLF更改为CR。unzip将然后将转换后的文件放回原位(并逐文件询问您-您可以回答:Yes-to-all)。感谢@vmsnomad指出这一点。

使用:

tr -d "\r" < file

看看在这里中使用sed的例子:

# In a 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 a 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

目前发布的解决方案只处理了部分问题,将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

注意,这将把文件的统一版本发送到标准输出。如果你想用统一版本替换文件,添加perl的-i标志。

这个问题可以用标准工具解决,但是对于粗心的人来说,有足够多的陷阱,我建议你安装flip命令,这是由zoo的作者Rahul Dhesi在20多年前写的。 它在转换文件格式方面做得很出色,例如,避免了二进制文件的无意破坏,如果您只是匆匆地更改看到的每个CRLF,这有点太容易了…

我试着

sed 's/^M$//' file.txt

OS X和其他几个方法(Fixing Dos Line ending .http://hintsforums.macworld.com/archive/index.php/t-125.html)。没有一个工作,文件保持不变(顺便说一下,Ctrl + V输入需要重新生成^M)。最后我使用了TextWrangler。它不是严格意义上的命令行,但它可以工作,而且不会抱怨。

如果你不能访问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))

(cross - posting from Super User.)

对于Mac OS X,如果你安装了家酿 (http://brew.sh/):

brew install dos2unix


for csv in *.csv; do dos2unix -c mac ${csv}; done;
确保您已经复制了文件,因为这个命令将在适当的位置修改文件。 -c mac选项使开关与OS x兼容

一个更简单的没有程序的AWK解决方案:

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

从技术上讲,“1”是您的程序,因为AWK在给定选项时需要一个。

或者,内部解决方案是:

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

这对我很有效

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

PCRE是超级简单的;

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

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

这将覆盖您的文件!

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

TIMTOWTDI !

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

基于戈登•戴维森的回答是

人们必须考虑[noeol]

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

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

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

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

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

我不得不思考同样的问题(在windows方面,但同样适用于Linux)。

令人惊讶的是,没有人提到一种非常自动化的CRLF <->文本文件的LF转换使用好的旧zip -ll选项(Info-ZIP):

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

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

zip --help的相关摘录:

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

有趣的是,在Windows上的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行结束符写入输出。

在Linux上,使用sed很容易将^M (Ctrl + )转换为*nix换行符(^J)。

在CLI中就像这样,文本中会有一个换行符。然而,\^J传递给sed:

sed 's/^M/\
/g' < ffmpeg.log > new.log

你可以在输入时使用^V (Ctrl + V), ^M (Ctrl + )和\(反斜杠)来得到:

sed 's/^V^M/\^V^J/g' < ffmpeg.log > new.log

安装dos2unix,然后就地转换文件

dos2unix <filename>

将转换后的文本输出到不同的文件使用

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

你可以在Ubuntu或Debian上安装它

sudo apt install dos2unix

或在macOS上使用家酿

brew install dos2unix

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

DOS到Unix:

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

Unix到DOS:

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

“集ff = unix / dos"表示将文件的fileformat (ff)更改为Unix/DOS行尾格式。

“:wq"意味着将文件写入磁盘并退出编辑器(允许在循环中使用该命令)。

sed -i.bak --expression='s/\r\n/\n/g' <file_path>

因为问题中提到了sed,所以这是使用sed实现此目的的最直接的方法。该表达式表示仅用换行符替换所有换行符和换行符。这就是你从Windows到Unix所需要的。我验证过了。

我根据接受的答案做了一个脚本,所以你可以直接转换它,而不需要一个额外的文件,然后删除和重命名。

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

只要确保你有一个像&;file1.txt",“file1.txt2"不存在,否则将被覆盖。我将此作为存储文件的临时位置。

在Bash 4.2及更新版本中,您可以使用类似这样的方法来剥离后面的CR,它只使用Bash内置:

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

只是补充@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>"

谢谢!🤗

(Ref (s)。 https://stackoverflow.com/a/3777853/3223785