如何以编程方式(不使用vi)将DOS/Windows换行符转换为Unix换行符?
dos2unix和unix2dos命令在某些系统上不可用。 如何使用sed、awk和tr等命令模拟它们?
如何以编程方式(不使用vi)将DOS/Windows换行符转换为Unix换行符?
dos2unix和unix2dos命令在某些系统上不可用。 如何使用sed、awk和tr等命令模拟它们?
当前回答
你可以使用AWK。将记录分隔符(RS)设置为匹配所有可能的换行符的正则表达式。并将输出记录分隔符(ORS)设置为unix样式的换行符。
awk 'BEGIN{RS="\r|\n|\r\n|\n\r";ORS="\n"}{print}' windows_or_macos.txt > unix.txt
其他回答
在Bash 4.2及更新版本中,您可以使用类似这样的方法来剥离后面的CR,它只使用Bash内置:
if [[ "${str: -1}" == $'\r' ]]; then
str="${str:: -1}"
fi
The solutions posted so far only deal with part of the problem, converting DOS/Windows' CRLF into Unix's LF; the part they're missing is that DOS use CRLF as a line separator, while Unix uses LF as a line terminator. The difference is that a DOS file (usually) won't have anything after the last line in the file, while Unix will. To do the conversion properly, you need to add that final LF (unless the file is zero-length, i.e. has no lines in it at all). My favorite incantation for this (with a little added logic to handle Mac-style CR-separated files, and not molest files that're already in unix format) is a bit of 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标志。
你可以使用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,或者dou和utod)并使用它们会更明智。
如果你需要处理整个目录和子目录,你可以使用zip:
zip -r -ll zipfile.zip somedir/
unzip zipfile.zip
这将创建一个zip存档,其中行结束符从CRLF更改为cr。unzip将然后将转换后的文件放回原位(并逐个文件询问您-您可以回答:yes to all)。感谢@vmsnomad指出这一点。
我不得不思考同样的问题(在windows方面,但同样适用于Linux)。
令人惊讶的是,没有人提到一种非常自动化的方法,使用旧的zip -ll选项(Info-ZIP)对文本文件进行CRLF <-> LF转换:
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)
使用AWK你可以做到:
awk '{ sub("\r$", ""); print }' dos.txt > unix.txt
使用Perl你可以做到:
perl -pe 's/\r$//' < dos.txt > unix.txt