在Unix中删除回车符

264

在Unix系统中,最简单的方法是删除文件中所有回车符\r


3
你是在谈论 '\r' '\n' 这两个字符,还是只是指那些讨厌的 '\r' 字符? - v3.
我认为使用 tr -d 命令是最简单的方法,但我想知道如何仅删除 最后一个回车符 - Yarco
@Yarco:这实际上已经在我的回答中涵盖了。最简单的并不总是正确的 :-) - paxdiablo
21个回答

305

我将假设你指的是回车符 (CR, "\r", 0x0d) 出现在行末,而不是在文件中任意位置(例如可能会出现在字符串中间)。使用此测试文件,只在第一行的末尾添加了一个 CR

$ cat infile
hello
goodbye

$ cat infile | od -c
0000000   h   e   l   l   o  \r  \n   g   o   o   d   b   y   e  \n
0000017

如果你的系统安装了 dos2unix,那么它就是最好的选择:

$ cat infile | dos2unix -U | od -c
0000000   h   e   l   l   o  \n   g   o   o   d   b   y   e  \n
0000016
如果因为某些原因你没有 dos2unix 可用,那么可以使用 sed 来实现:

如果由于某种原因您无法使用 dos2unix,那么可以使用sed来实现:

$ cat infile | sed 's/\r$//' | od -c
0000000   h   e   l   l   o  \n   g   o   o   d   b   y   e  \n
0000016

如果由于某些原因您无法使用sed,那么ed也可以实现,但需要采用复杂的方式:

$ echo ',s/\r\n/\n/
> w !cat
> Q' | ed infile 2>/dev/null | od -c
0000000   h   e   l   l   o  \n   g   o   o   d   b   y   e  \n
0000016

如果您的计算机上没有安装任何这些工具,那么您面临的问题比尝试转换文件更严重 :-)


16
仅限于使用GNU sed命令时,\r 才能生效。否则,您可以使用以下方式: sed \echo "s/\r//"`` - lapo
16
在MacOS上,sedecho都不能识别\r。在这种情况下,只有printf "\r"可以正常工作。 - Steve Powell
36
补充@steve的评论:在Mac上,请使用以下命令:sed "s/$(printf '\r')\$//" - mklement0
7
为了在 Mac 上修复问题,您还可以在单引号的 sed 字符串前加上 $,就像这样:sed $'s@\r@@g' |od -c(但如果要替换为 \n,则需要转义) - nhed
2
我不是100%确定,但对于OS X来说,使用CTRL-V + CTRL-M代替\r似乎可以起作用。 - user456814
显示剩余10条评论

272
tr -d '\r' < infile > outfile

请参阅tr(1)


4
不太好:1. 不能原地操作,2. 可以替换 \r,但不仅限于行尾(这可能是你想要的,也可能不是)。 - Tomasz Gandor
13
  1. 大多数类Unix工具都是这样工作的,这通常是最安全的方式,因为如果出了问题,你仍然拥有原始文件。
  2. 所提出的问题是要去除回车符,而不是转换行尾。但是还有很多其他答案可能更适合您。
- Henrik Gustafsson
2
如果你的 tr 不支持 \r 转义,请尝试使用 '\015' 或者直接使用字面量 '^M'(在许多终端和 shell 中,按下 ctrl-V 和 ctrl-M 将会产生一个字面上的 ctrl-M 字符)。 - tripleee
那么当您想要 outfile = infile 时,该如何更改呢? - Chris
4
@donlan,回复晚了,但通常你可以使用类似这样的命令:someProg <in >out && mv out in - paxdiablo
感谢@HenrikGustafsson - 这对于在运行WSL(Ubuntu)的Win10上使用wget %0D 'padding'非常有效。 tr -d'\r'<my_original_file.sh> my_out_file.sh - semmyk-research

53

在我看来,Linux 上最简单的方法是:

sed -i.bak 's/\r$//g' <filename>

-i会就地编辑文件,而.bak会通过复制文件并在结尾处添加扩展名.bak来创建原始文件的备份。(您可以在-i后指定任何内容,或者只指定 -i 以不创建备份。)

对于替换操作符's/\r//'强引号必要的。如果没有强引号,shell会将\r解释为转义符+r,并将其简化为普通的r,并删除所有小写r。这就是为什么2009年由Rob给出的答案不起作用的原因。

添加/g修饰符可以确保即使有多个\r也会被删除,而不仅仅是第一个。


我建议不要使用“-i”标志,因为它会修改原始文件,如果您希望保持不变,则可能会很危险。 - zolastro
2
不要只使用-i,而是使用-i.bak。这将创建一个带有.bak扩展名的原始文件备份。 - Angel115
如果你正在匹配 \r$ ,那么 /g 就没有用了,因为它只会替换行末的最后一个字符。例如 printf 'foo\r\r\r\n' | sed 's/\r$//g' | od -c 会保留两个 \r's/\r\+$//' 将会达到你想要的效果(虽然我不知道重复的回车符是否真的需要关注)。 - dimo414

40

老派方法:

tr -d '\r' < filewithcarriagereturns > filewithoutcarriagereturns

30

许多系统都存在一个叫做 dos2unix 的实用工具,并且可以在大多数系统上轻松安装。


6
有时它也被称为 fromdos(和todos)。 - Anonymous
链接已经失效,请访问http://dos2unix.sourceforge.net/。 - RyanQuey

9

sed -i s/\r// <filename> 或类似的命令;请参阅man sed或有关使用sed的丰富信息。

需要指出的一点是上述中“回车符”的确切含义;如果您真正意思是单个控制字符“回车符”,那么上面的模式是正确的。如果您更一般地指的是CRLF(回车符和换行符,这是Windows下实现换行符的方式),那么您可能想要替换\r\n。在Linux / Unix中,裸换行符(newline)是\n


我正在尝试使用 --> sed 's/\r\n/=/' countryNew.txt > demo.txt,但它不起作用。 "老虎" "狮子。" - Suvasis
我们应该理解为你在使用Mac吗?我注意到Darwin sed默认情况下似乎与大多数Linux版本具有不同的命令和功能集。 - jsh
4
FYI,“s/\r//”似乎不能删除OS X上的回车符,它似乎只能删除字面上的r字符。我还不确定原因是什么。也许与字符串的引用方式有关?作为解决方法,可以使用“CTRL-V + CTRL-M”代替\r - user456814
请查看答案 https://dev59.com/-nRA5IYBdhLWcg3w2x2W#41461947 中的注释! - Leponzo

7
如果您是Vi用户,您可以打开文件并使用以下命令删除回车符:
:%s/\r//g

或者使用

:1,$ s/^M//

请注意,您应该通过按ctrl-v然后按ctrl-m来输入^M。

3
如果文件的每一行都有回车符(即正确的DOS文件),vim将使用filetype=dos加载它,并且不会显示^M。解决这个问题需要大量击键,这不是vim的设计初衷。我只会用sed -i,然后使用-e 's/\r$//g'来限制删除EOL处的CR。 - Tomasz Gandor

6

有人建议使用 dos2unix,我也强烈推荐。这里我只是提供更多细节。

如果已安装,请跳到下一步。如果尚未安装,建议通过 yum 安装,例如:

yum install dos2unix

然后你可以像这样使用它:

dos2unix fileIWantToRemoveWindowsReturnsFrom.txt

6

再次提供一种解决方案...因为总有更多的解决方案:

perl -i -pe 's/\r//' filename

这很好,因为它可以在我使用过的所有Unix/Linux系统中的任何版本上运行并且已经就位。


如果您想要备份原始文件,建议使用“-i.bak”。 - MarkHu

4

在任何UNIX®系统上删除\r:

这个问题中大多数现有的解决方案都是GNU特定的,不能在OS X或BSD上工作;下面的解决方案应该适用于更多的UNIX系统,并且在任何shell中(从tcshsh),甚至在GNU / Linux上也可以使用。

在OS X、OpenBSD和NetBSD中,在tcsh中测试,以及在Debian GNU/Linux中的bash中测试。


使用sed

在OS X的tcsh中,以下sed片段可以与printf一起使用,因为sedecho都不像GNU那样特殊处理\r

sed `printf 's/\r$//g'` input > output

使用 tr 命令:

另一种选项是使用 tr 命令:

tr -d '\r' < input > output

sedtr之间的区别:

看起来,tr会保留输入文件中缺少的结尾换行符,而sed在OS X和NetBSD上(但不是在OpenBSD或GNU / Linux上)即使输入文件在结尾处缺少任何结尾\r\n,也会在文件末尾插入一个结尾换行符。


测试:

以下是一些示例测试,可用于确保此功能在您的系统上正常工作,使用printfhexdump -C;或者如果您的系统缺少hexdump,也可以使用od -c

% printf 'a\r\nb\r\nc' | hexdump -C
00000000  61 0d 0a 62 0d 0a 63                              |a..b..c|
00000007
% printf 'a\r\nb\r\nc' | ( sed `printf 's/\r$//g'` /dev/stdin > /dev/stdout ) | hexdump -C
00000000  61 0a 62 0a 63 0a                                 |a.b.c.|
00000006
% printf 'a\r\nb\r\nc' | ( tr -d '\r' < /dev/stdin > /dev/stdout ) | hexdump -C
00000000  61 0a 62 0a 63                                    |a.b.c|
00000005
% 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接