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

Kor*_*vik 313 unix linux windows bash newline

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

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

Jon*_*ler 311

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

tr -d '\015' <DOS-file >UNIX-file
Run Code Online (Sandbox Code Playgroud)

请注意,名称与名称DOS-file不同UNIX-file; 如果您尝试两次使用相同的名称,则最终文件中不会包含任何数据.

你不能反过来做(使用标准'tr').

如果你知道如何在一个脚本中输入回车符(control-V,control-M输入control-M),那么:

sed 's/^M$//'     # DOS to Unix
sed 's/$/^M/'     # Unix to DOS
Run Code Online (Sandbox Code Playgroud)

其中'^ M'是控制-M字符.您还可以使用bash ANSI-C Quoting机制指定回车:

sed $'s/\r$//'     # DOS to Unix
sed $'s/$/\r/'     # Unix to DOS
Run Code Online (Sandbox Code Playgroud)

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

  • 使用`tr -d'\ 015'<DOS-file> UNIX-file`,其中`DOS-file` ==`UNIX-file`只会产生一个空文件.不幸的是,输出文件必须是不同的文件. (7认同)
  • 有地方; 你必须知道在哪里找到它们.在限制范围内,GNU`sed`选项`-i`(就地)可以工作; 限制是链接文件和符号链接.`sort`命令有'always'(自1979年以来,如果不是更早)支持`-o`选项,它可以列出其中一个输入文件.但是,这部分是因为`sort`在写入任何输出之前必须读取其所有输入.其他程序偶尔会支持覆盖其中一个输入文件.您可以找到一个通用程序(脚本)来避免Kernighan&Pike的"UNIX编程环境"中的问题. (4认同)
  • @ButtleButkus:嗯,是的; 这就是我用两个不同名字的原因.如果在程序全部读取之前删除输入文件,就像两次使用相同名称时一样,最终会得到一个空文件.这是类Unix系统上的统一行为.它需要特殊的代码来安全地覆盖输入文件.按照说明进行操作即可. (3认同)
  • 第三种选择对我有用,谢谢.我确实使用了-i选项:`sed -i $'s /\r $ $''filename`来进行编辑.我正在使用无法访问互联网的计算机,因此软件安装是一个问题. (3认同)
  • @JonathanLeffler 通用程序称为`sponge`,可以在[moreutils](https://joeyh.name/code/moreutils/) 中找到:`tr -d '\015' &lt; original_file | 海绵 original_file`。我每天都使用它。 (3认同)

gho*_*g74 60

tr -d "\r" < file
Run Code Online (Sandbox Code Playgroud)

看看这里使用的例子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
Run Code Online (Sandbox Code Playgroud)

使用sed -i就地转化例如sed -i 's/..../' file.

  • 我使用了一个变体,因为我的文件只有`\ r`:`tr"\ r""\n"<infile> outfile` (10认同)
  • 请注意,建议的`\ r``到`\n`映射具有双倍间隔文件的效果; 在DOS中结束的每一条CRLF行在Unix中变为`\n \n`. (4认同)

小智 37

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

要删除回车:

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

要添加回车:

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

  • 看起来像[POSIX`tr`支持`\ r``.](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tr.html#tag_20_132_13)所以你也可以使用`printf'%s \n ''%!tr -d"\ r"'x | ex file`(虽然被授予,但即使不在`\n`之前,也删除了`\ r``).另外,POSIX没有指定`ex`的`-b`选项. (2认同)

cod*_*ict 24

使用AWK你可以做到:

awk '{ sub("\r$", ""); print }' dos.txt > unix.txt
Run Code Online (Sandbox Code Playgroud)

使用Perl你可以做到:

perl -pe 's/\r$//' < dos.txt > unix.txt
Run Code Online (Sandbox Code Playgroud)

  • 一个不错的_portable_`awk`解决方案. (2认同)

Nor*_*sey 19

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


Joh*_*ola 18

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

Dos到Unix:

vim file.txt -c "set ff=unix" -c ":wq"
Run Code Online (Sandbox Code Playgroud)

Unix到dos:

vim file.txt -c "set ff=dos" -c ":wq"
Run Code Online (Sandbox Code Playgroud)

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

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

  • 您可以使用“:x”而不是“:wq” (3认同)
  • 这似乎是最优雅的解决方案,但是不幸的是,对于wq的含义缺乏解释。 (2认同)
  • 任何使用`vi`的人都会知道`:wq`是什么意思。对于那些不包含3个字符的字符,则意味着1)打开vi命令区域,2)写入和3)退出。 (2认同)

Gor*_*son 15

到目前为止发布的解决方案只处理部分问题,将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
Run Code Online (Sandbox Code Playgroud)

请注意,这会将文件的Unixified版本发送到stdout.如果要使用Unixified版本替换该文件,请添加perl的-i标志.

  • 抓取我的数据文件。xD某处出错 (2认同)

ana*_*nik 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))
Run Code Online (Sandbox Code Playgroud)

超级用户交叉发布.

  • 用法具有误导性。真正的`dos2unix` 默认会转换*所有* 输入文件。您的用法暗示了 `-n` 参数。真正的 `dos2unix` 是一个过滤器,它从标准输入读取,如果没有给出文件,则写入标准输出。 (2认同)

Bor*_*ris 13

要就地转换文件

dos2unix <filename>
Run Code Online (Sandbox Code Playgroud)

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

dos2unix -n <input-file> <output-file>
Run Code Online (Sandbox Code Playgroud)

您可以使用

sudo apt install dos2unix
Run Code Online (Sandbox Code Playgroud)

或在MacOS上使用自制软件

brew install dos2unix
Run Code Online (Sandbox Code Playgroud)

  • 我知道这个问题要求 dos2unix 的替代品,但这是第一个谷歌结果。 (4认同)

Tho*_*ner 8

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

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

#!/usr/bin/env bash
perl -pi -e 's/\r\n/\n/g' -- $@
Run Code Online (Sandbox Code Playgroud)

这将覆盖您的文件!

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


naw*_*awK 6

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

awk -v ORS='\r\n' '1' unix.txt > dos.txt
Run Code Online (Sandbox Code Playgroud)

技术上'1'是你的程序,b/c awk在给定选项时需要一个.

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

while IFS= read -r line;
do printf '%s\n' "${line%$'\r'}";
done < dos.txt > unix.txt
Run Code Online (Sandbox Code Playgroud)

  • 这是故意的,留给作者练习._eyerolls_`awk -v RS ='\ r \n''1'dos.txt> unix.txt` (5认同)
  • 纯 bash 解决方案很有趣,但比等效的“awk”或“sed”解决方案慢得多。另外,您必须使用 while IFS= read -r line 来忠实地保留输入行,否则前导和尾随空格将被修剪(或者,在 read 命令中不使用变量名并使用 $REPLY)。 (2认同)

小智 5

我只是想思考同样的问题(在 Windows 端,但同样适用于 Linux)。

\n

zip -ll令人惊讶的是,没有人提到使用旧选项(Info-ZIP)对文本文件进行 CRLF\xc2\xa0<->\xc2\xa0LF 转换的非常自动化的方法:

\n
zip -ll textfiles-lf.zip files-with-crlf-eol.*\nunzip textfiles-lf.zip\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

相关摘录自zip --help

\n
zip --help\n...\n-l   convert LF to CR LF (-ll CR LF to LF)\n
Run Code Online (Sandbox Code Playgroud)\n


use*_*755 5

有趣的是,我在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
Run Code Online (Sandbox Code Playgroud)

我的猜测是,sed在从输入中读取行时会忽略它们,并始终在输出中写入unix行尾。

  • 不过,在像 GNU/Linux 这样的 LF 类型系统上,`sed ""` 不起作用。 (2认同)