什么是换行符 - '\n'

15

这是一个非常基础的概念,但我从未能很好地表达出来。我想尝试拼写一下并看看我错在哪里。

如果必须要定义“换行符”,那该怎么做呢?比如我在Unix(或Windows)中创建一个新文件,那么文件是否通过在文件中插入一个特殊字符来存储“行末”信息,这个特殊字符被称为“换行符”?如果是这样的话,它的ASCII值是多少?我记得在C程序中,我会检查读取的字符是否等于'\n'的值。还有为什么这两个令人困惑的字符被用来表示行末字符呢?

bash$ cat states
California
Massachusetts
Arizona

假设我想在两行之间插入一行空白,并且希望输出格式如下:

Desired output:
California

Massachusetts

Arizona

bash$sed -e 's/\n/\n\n/g' states  does not work.
为什么我不能像处理其他字符一样处理“换行符”,并执行类似上面的命令。(我知道有人可能会说这是sed语法问题,但是请解释一下不允许这样做的原因,以便我能消除困惑。)
同样,在vim编辑器中,我不能使用:%s/\n/\n\n/g。为什么?
在sed和vim内部,我需要进一步用反斜杠转义\n吗?
谢谢,
Jagrati

3
为什么要用这两个让人困惑的字符代表行尾字符呢?对于程序来说,实际上并不是两个字符,而是一个字符被反斜杠所“转义”。编译器理解它代表的值与普通ASCII的n不同。字符转义在许多语言和平台中被广泛使用,用于表示你无法直接表示的字符。 - GalacticCowboy
2
深入解释Galactic Cowboy所说的,\n不是换行符,它是在C字符和字符串字面量(以及其他一些上下文中)表示换行符的符号。源代码中实际的真正换行符当然是看不见的,除非它结束了该行。这就是为什么你在使用sed时会遇到问题:\n在该程序中并不代表换行符。 - Tyler McHenry
2
我发誓我读到了“新手字符是什么 - '\n'”,太累了。 - Enriquev
8个回答

22

换行符(\n)的ASCII码是10(0xA),回车符(\r)的ASCII码是13(0xD)。

不同的操作系统为文件选择了不同的行尾表示方式。Windows使用CRLF(\r\n),Unix使用LF(\n)。旧版Mac OS使用CR(\r),但OS X切换到了Unix字符。

这里有一个相对有用的FAQ


11
OS 9 使用 \r;在 OS X 中他们放弃了它并切换到与 Unix 匹配。 - Michael Mrozek
1
好的,已经修复了。你们知道吗,你们也可以编辑答案。 :) - i_am_jorf
+1。但是你提到了LF,却没有明确它是什么或代表什么。 :) - user353297
Windows使用\r\n作为换行符。但是即使在Windows中,“hello, world!\n”也会按预期打印一个新行!!! - Sourav Kannantha B

12

根据sed手册页面的说法:

通常,sed将输入的一行(不包括终止换行符)循环复制到模式空间中(除非"D"函数后有剩余内容),应用所有选择该模式空间的地址的命令,将模式空间复制到标准输出中并添加一个换行符,然后删除模式空间。

它是在没有换行符的情况下操作该行,因此你那里的模式永远无法匹配。你需要做一些其他的事情,比如匹配$(行末)或^(行首)。

这里是一些适用于我的示例:

$ cat > states
California
Massachusetts
Arizona
$ sed -e 's/$/\
> /' states
California

Massachusetts

Arizona

sed命令的代码行后,我输入了一个文字换行符。


"\n" 在 sed 中是有效的,因此您也可以只使用 sed 's/$/\n/' states - jabirali

6
转义字符取决于解释它们的系统。许多编程语言将\n 解释为换行符,但并不一定适用于您提到的其他实用程序。即使它们也将\n 视为换行符,也可能存在其他技术可使其按您所需进行操作。您需要查阅它们的文档(或查看此处的其他答案)。对于DOS / Windows系统,换行符实际上是两个字符:回车符(ASCII 13,也称为\r),后跟换行符(ASCII 10)。在Unix系统(包括Mac OSX)中,它只是一个换行符。在旧版Mac中,它是一个单独的回车符。

3
sed 's/$/\n/' states

在使用 us-ascii 字符集编码的文件中,该文件无效。您必须获取 ASCII 代码。 - ssoto

1
我看到很多sed的答案,但没有vim的。公平地说,vim对换行符的处理有点令人困惑。搜索\n,但替换为\r。我建议阅读手册::help pattern一般和:help NL-used-for-Nul特别是。要使用:substitute命令实现你想要的功能,
:%s/\_$/\r

虽然我认为大多数人会使用类似的东西

:g/^/put=''

为了达到相同的效果。

这里有一种方法可以让你自己找到答案。运行你的文件通过xxd,它是标准vim分发包的一部分。

:%!xxd

你得到

0000000: 4361 6c69 666f 726e 6961 0a4d 6173 7361  California.Massa
0000010: 6368 7573 6574 7473 0a41 7269 7a6f 6e61  chusetts.Arizona
0000020: 0a                                       .

这表明46是C的十六进制代码,61是a的代码,依此类推。特别地,0a(十进制10)是\n的代码。只是为了好玩,试试吧。

:set ff=dos

在通过xxd进行过滤之前,您将看到0d0a(CRLF)作为行终止符。

:help /\_$
:help :g
:help :put
:help :!
:help 23.4

1

sed 可以进入多行搜索和替换模式来匹配换行符 \n

为此,sed 首先必须将整个文件或字符串读入保持缓冲区(“保持空间”),以便它可以将文件或字符串内容视为“模式空间”中的单个行。

要可移植地替换单个换行符(针对 GNU 和 FreeBSD sed),您可以使用转义的“真实”换行符。

# cf. http://austinmatzko.com/2008/04/26/sed-multi-line-search-and-replace/
echo 'California
Massachusetts
Arizona' | 
sed -n -e '
# if the first line copy the pattern to the hold buffer
1h
# if not the first line then append the pattern to the hold buffer
1!H
# if the last line then ...
$ {
# copy from the hold to the pattern buffer
g
# double newlines
s/\n/\
\
/g
s/$/\
/
p
}'

# output
# California
#
# Massachusetts
#
# Arizona
#

然而,有一种更方便的方法可以实现相同的结果:
echo 'California
Massachusetts
Arizona' | 
   sed G

1

我觉得 Jeff Attwood 的这篇文章完美地回答了你的问题。它详细介绍了 Dos、Mac 和 Unix 上换行符之间的差异,并解释了 CR(回车)和 LF(换行)的历史。


那篇文章大致上讲述了问题的基本要点,但它也存在一些事实错误和半真半假的内容。你最好阅读维基百科的换行符主题。 - Adrian McCarthy

0

试试这个:

$ sed -e $'s/\n/\n\n/g' states

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