1586

如何使用该命令将换行符 (" \n")替换为空格 (" ") ?sed

我尝试失败:

sed 's#\n# #g' file
sed 's#^$# #g' file

我如何解决它?

4

43 回答 43

1887

sed旨在用于基于行的输入。虽然它可以做你需要的。


这里更好的选择是使用tr如下命令:

tr '\n' ' ' < input_filename

或完全删除换行符:

tr -d '\n' < input.txt > output.txt

或者如果你有 GNU 版本(带有长选项)

tr --delete '\n' < input.txt > output.txt
于 2009-08-09T19:16:41.047 回答
1690

将此解决方案与 GNU 一起使用sed

sed ':a;N;$!ba;s/\n/ /g' file

这将在循环中读取整个文件 ( ':a;N;$!ba),然后用空格 ( ) 替换换行符s/\n/ /g。如果需要,可以简单地附加额外的替换。

解释:

  1. sed首先将第一行(不包括换行符)读入模式空间。
  2. 通过创建标签:a
  3. 通过 . 将换行符和下一行添加到模式空间N
  4. 如果我们在最后一行之前,则分支到创建的标签$!ba$!意味着不在最后一行执行。这是避免N再次执行的必要条件,如果没有更多输入,则会终止脚本!)。
  5. 最后,替换用模式空间(即整个文件)上的空格替换每个换行符。

这是适用于 BSD 和 OS X 的跨平台兼容语法sed(根据@Benjie 评论):

sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' file

如您所见,sed用于这个原本简单的问题是有问题的。有关更简单和适当的解决方案,请参阅此答案

于 2009-08-09T20:26:21.843 回答
570

快速回答

sed ':a;N;$!ba;s/\n/ /g' file
  1. :a 创建一个标签 'a'
  2. N 将下一行追加到模式空间
  3. 美元! 如果不是最后一行,则ba 分支(转到)标签“a”
  4. s 替换/\n/ 正则表达式换行// 空格/g 全局匹配(尽可能多次)

sed 将循环执行步骤 1 到 3,直到到达最后一行,使所有行都适合 sed 将替换所有 \n 字符的模式空间


备择方案

所有替代方案,与sed不同,不需要到达最后一行即可开始该过程

bash,慢

while read line; do printf "%s" "$line "; done < file

perlsed类似的速度

perl -p -e 's/\n/ /' file

with tr,比sed快,只能用一个字符替换

tr '\n' ' ' < file

使用paste类似 tr的速度,只能用一个字符替换

paste -s -d ' ' file

awk , tr类似的速度

awk 1 ORS=' ' file

像“echo $(< file)”这样的其他替代方法很慢,只适用于小文件,需要处理整个文件才能开始处理。


sed FAQ 5.10的长答案

5.10。为什么我不能使用 \n 转义
序列匹配或删除换行符?为什么我不能使用 \n 匹配 2 行或更多行?

\n 永远不会匹配行尾的换行符,因为
换行符总是在将行放入
模式空间之前被剥离。要将 2 行或更多行放入模式空间,请使用
“N”命令或类似命令(例如“H;...;g;”)。

Sed 的工作方式如下: sed 一次读取一行,删除
终止的换行符,将剩下的内容放入
sed 脚本可以寻址或更改它的模式空间中,当
打印模式空间时,将换行符附加到 stdout (或文件)。如果
使用“d”或“D”完全或部分删除模式空间,则在这种情况下
添加 换行符。因此,像这样的脚本

  sed 's/\n//' file       # to delete newlines from each line             
  sed 's/\n/foo\n/' file  # to add a word to the end of each line         

将永远不会工作,因为在 将行放入模式空间之前删除了尾随换行符。
要执行上述任务,请
改用以下脚本之一:

  tr -d '\n' < file              # use tr to delete newlines              
  sed ':a;N;$!ba;s/\n//g' file   # GNU sed to delete newlines             
  sed 's/$/ foo/' file           # add "foo" to end of each line          

由于 GNU sed 以外的 sed 版本对
模式缓冲区的大小有限制,因此此处首选 Unix 'tr' 实用程序。
如果文件的最后一行包含换行符,GNU sed 会
将该换行符添加到输出中,但会删除所有其他换行符,而 tr 将
删除所有换行符。

要匹配两行或多行的块,有 3 个基本选择:
(1) 使用“N”命令将下一行添加到模式空间;
(2) 使用'H'命令至少两次将当前行追加
到Hold space,然后
用x、g或G从hold space中检索行;或 (3) 使用地址范围(参见上文第 3.3 节)
来匹配两个指定地址之间的行。

选项 (1) 和 (2) 会将 \n 放入模式空间中,
可以根据需要对其进行寻址 ('s/ABC\nXYZ/alphabet/g')。使用 'N' 删除一行行的一个示例
出现在第 4.13 节
(“如何删除一个特定连续行的块?”)。
可以通过将删除命令更改为其他内容来修改此示例
,例如“p”(打印)、“i”(插入)、“c”(更改)、“a”(追加)
或“s”(替换) .

选择 (3) 不会将 \n 放入模式空间,但它
匹配连续行的块,因此您可能
甚至不需要 \n 来查找您要查找的内容。由于 GNU sed
版本 3.02.80 现在支持这种语法:

  sed '/start/,+4d'  # to delete "start" plus the next 4 lines,           

除了传统的 '/from here/,/to there/{...}' 范围
地址之外,还可以完全避免使用 \n。

于 2011-10-08T14:55:20.210 回答
240

更短的 awk 替代方案:

awk 1 ORS=' '

解释

awk 程序由包含条件代码块的规则组成,即:

condition { code-block }

如果省略代码块,则使用默认值:{ print $0 }. 因此,1被解释为真实条件并print $0为每一行执行。

awk读取输入时,它根据 (Record Separator) 的值将其拆分为记录RS,默认情况下是换行符,因此awk默认情况下会逐行解析输入。RS拆分还涉及从输入记录中剥离。

现在,当打印一条记录时,ORS(输出记录分隔符)被附加到它上面,默认又是一个换行符。因此,通过更改ORS为空格,所有换行符都更改为空格。

于 2013-02-13T12:12:59.400 回答
204

GNU sed 有一个选项 ,-z用于空分隔的记录(行)。你可以打电话:

sed -z 's/\n/ /g'
于 2015-05-05T09:43:37.790 回答
93

Perl版本按您预期的方式工作。

perl -i -p -e 's/\n//' file

正如评论中所指出的,值得注意的是,此编辑已到位。-i.bak将在替换之前为您提供原始文件的备份,以防您的正则表达式不如您想象的那么聪明。

于 2009-08-09T19:25:26.897 回答
47

谁需要sed?这是bash方法:

cat test.txt |  while read line; do echo -n "$line "; done
于 2010-08-11T12:07:33.670 回答
29

为了使用 awk 将所有换行符替换为空格,而不将整个文件读入内存:

awk '{printf "%s ", $0}' inputfile

如果你想要一个最后的换行符:

awk '{printf "%s ", $0} END {printf "\n"}' inputfile

您可以使用空格以外的字符:

awk '{printf "%s|", $0} END {printf "\n"}' inputfile
于 2012-03-30T06:41:01.903 回答
26
tr '\n' ' ' 

是命令。

简单易用。

于 2014-04-13T19:01:42.610 回答
19

三件事。

  1. tr(或cat,等)绝对不需要。(GNU)sed和 (GNU)awk结合使用时,可以完成您需要的任何文本处理的 99.9%。

  2. 流!=基于行。ed是一个基于行的编辑器。sed不是。有关差异的更多信息,请参阅sed 讲座。大多数人混淆sed是基于行的,因为默认情况下,它在简单匹配的模式匹配中不是很贪婪 - 例如,在进行模式搜索和替换一个或两个字符时,它默认只替换第一个匹配它会找到(除非全局命令另有指定)。如果它是基于行而不是基于流的,甚至不会有全局命令,因为它一次只会评估行。尝试运行ed;你会注意到不同之处。ed如果您想遍历特定行(例如在 for 循环中),这非常有用,但大多数时候您只需要sed.

  3. 话虽如此,

    sed -e '{:q;N;s/\n/ /g;t q}' file
    

    sed在 GNU版本 4.2.1中工作得很好。上面的命令将用空格替换所有换行符。输入起来很丑陋而且有点麻烦,但它工作得很好。' {}s 可以省略,因为它们只是出于理智的原因才包括在内。

于 2011-05-01T11:04:46.770 回答
14

易于理解的解决方案

我有这个问题。更重要的是,我需要在 BSD(Mac OS X)和 GNU(Linux 和Cygwin)上工作的解决方案,sed并且tr

$ echo 'foo
bar
baz


foo2
bar2
baz2' \
| tr '\n' '\000' \
| sed 's:\x00\x00.*:\n:g' \
| tr '\000' '\n'

输出:

foo
bar
baz

(有尾随换行符)

它可以在 Linux、OS X 和 BSD 上运行——即使没有UTF-8支持或使用蹩脚的终端。

  1. 用于tr将换行符与另一个字符交换。

    NULL(\000\x00) 很好,因为它不需要 UTF-8 支持并且不太可能被使用。

  2. 用于sed匹配NULL

  3. 如果需要,用于tr换回额外的换行符

于 2012-01-25T02:52:32.237 回答
14

为什么我没有找到一个简单的解决方案awk

awk '{printf $0}' file

printf如果您想用空格或其他分隔原始行,将打印没有换行符的每一行:

awk '{printf $0 " "}' file
于 2020-03-15T20:24:10.323 回答
13

带有 :a 标签的答案...

如何使用 sed 替换换行符 (\n)?

... 在命令行上的 freebsd 7.2 中不起作用:

(回声富;回声栏)| sed ':a;N;$!ba;s/\n/ /g'
sed: 1: ":a;N;$!ba;s/\n/ /g": 未使用的标签 'a;N;$!ba;s/\n/ /g'
富
酒吧

但是,如果您将 sed 脚本放在文件中或使用 -e “构建” sed 脚本...

> (echo foo; 回声栏) | sed -e :a -e N -e '$!ba' -e 's/\n/ /g'
富吧

或者 ...

> cat > x.sed << eof
:a
N
$!ba
s/\n/ /g
eof

> (echo foo; echo bar) | sed -f x.sed
foo bar

也许 OS X 中的 sed 是类似的。

于 2009-09-24T22:26:51.057 回答
13

您可以使用xargs

seq 10 | xargs

或者

seq 10 | xargs echo -n
于 2014-05-16T21:18:20.537 回答
11

如果您不幸不得不处理 Windows 行尾,则需要删除\r\n

tr '\r\n' ' ' < $input > $output
于 2019-04-09T22:47:41.903 回答
9

我不是专家,但我想sed你首先需要将下一行附加到模式空间中,bij 使用“ N”。从书sed & awk的“高级 sed 命令”中的“多行模式空间”部分(Dale Dougherty 和 Arnold Robbins;O'Reilly 1997;预览中的第 107 页):

multiline Next (N) 命令通过读取新的输入行并将其附加到模式空间的内容中来创建多行模式空间。模式空间的原始内容和新的输入行由换行符分隔。嵌入的换行符可以通过转义序列“\n”在模式中匹配。在多行模式空间中,元字符“^”匹配模式空间的第一个字符,而不是任何嵌入换行符之后的字符。同样,“$”仅匹配模式空间中的最后一个换行符,而不匹配任何嵌入的换行符。执行 Next 命令后,控制权将传递给脚本中的后续命令。

来自man sed

[2地址]N

将下一行输入附加到模式空间,使用嵌入的换行符将附加的材料与原始内容分开。请注意,当前行号会发生变化。

用它来搜索(多个)格式错误的日志文件,其中搜索字符串可能在“孤立”的下一行中找到。

于 2009-08-09T20:23:24.580 回答
7

针对上面的“tr”解决方案,在 Windows 上(可能使用 tr 的 Gnuwin32 版本),建议的解决方案:

tr '\n' ' ' < input

对我不起作用,它要么出错,要么由于某种原因实际上替换了 \nw/ '' 。

使用 tr 的另一个功能,“删除”选项 -d 确实有效:

tr -d '\n' < input

或 '\r\n' 而不是 '\n'

于 2011-02-25T22:54:36.513 回答
7

我使用混合方法来解决换行问题,方法是使用 tr 用制表符替换换行符,然后用我想要的任何内容替换制表符。在这种情况下,“
”因为我正在尝试生成 HTML 中断。

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`
于 2012-03-12T20:13:45.807 回答
5

在某些情况下,也许您可​​以更改RS为其他字符串或字符。这样,\n 可用于 sub/gsub:

$ gawk 'BEGIN {RS="dn" } {gsub("\n"," ") ;print $0 }' file

shell 脚本的强大之处在于,如果您不知道如何以一种方式执行它,您可以以另一种方式执行它。很多时候,你需要考虑的事情比对简单问题的复杂解决方案还要多。

关于 gawk 很慢......并将文件读入内存的事情,我不知道这一点,但对我来说 gawk 似乎当时只使用一行并且非常非常快(不像其他一些那么快,但编写和测试的时间也很重要)。

我处理 MB 甚至 GB 的数据,我发现的唯一限制是行大小。

于 2011-10-19T09:20:37.003 回答
5

防弹解决方案。二进制数据安全且符合 POSIX,但速度较慢。

POSIX sed 需要根据 POSIX 文本文件POSIX 行 定义进行输入,因此不允许使用 NULL 字节和过长的行,并且每行必须以换行符结尾(包括最后一行)。这使得很难使用 sed 处理任意输入数据。

以下解决方案避免使用 sed,而是将输入字节转换为八进制代码,然后再次转换为字节,但截取八进制代码 012(换行符)并输出替换字符串来代替它。据我所知,该解决方案符合 POSIX 标准,因此它应该适用于各种平台。

od -A n -t o1 -v | tr ' \t' '\n\n' | grep . |
  while read x; do [ "0$x" -eq 012 ] && printf '<br>\n' || printf "\\$x"; done

POSIX 参考文档: shshell 命令语言odtrgrepread[printf

read,[和至少在 bash 中都是printf内置的,但 POSIX 可能无法保证这一点,因此在某些平台上,每个输入字节可能会启动一个或多个新进程,这会减慢速度。即使在 bash 中,这个解决方案也只能达到大约 50 kB/s,因此它不适合大文件。

在 Ubuntu(bash、dash 和 busybox)、FreeBSD 和 OpenBSD 上测试。

于 2014-04-19T06:15:37.103 回答
5

您也可以使用此方法:

sed 'x;G;1!h;s/\n/ /g;$!d'

解释

x   - which is used to exchange the data from both space (pattern and hold).
G   - which is used to append the data from hold space to pattern space.
h   - which is used to copy the pattern space to hold space.
1!h - During first line won't copy pattern space to hold space due to \n is
      available in pattern space.
$!d - Clear the pattern space every time before getting the next line until the
      the last line.

流动

当第一行从输入中得到时,进行交换,因此1进入保持空间并\n进入模式空间,将保持空间附加到模式空间,并执行替换并删除模式空间。

在第二行,进行交换,2进入保持空间并1进入模式空间,G将保持空间附加到模式空间,h将模式复制到其中,进行替换并删除。此操作一直持续到达到 EOF 并打印准确的结果。

于 2014-07-18T06:44:34.357 回答
5

使用allow查找和替换\n

sed -ie -z 's/Marker\n/# Marker Comment\nMarker\n/g' myfile.txt

标记

变成

# 标记注释

标记

于 2018-07-17T07:33:03.943 回答
4

您可以使用xargs- 默认情况下它将替换\n为空格。

但是,如果您的输入有任何大小写unterminated quote,例如如果给定行上的引号不匹配,则会出现问题。

于 2013-03-28T15:06:25.657 回答
3

在 Mac OS X 上(使用 FreeBSD sed):

# replace each newline with a space
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g; ta'
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g' -e ta
于 2010-07-28T10:44:38.777 回答
3

要删除空行:

sed -n "s/^$//;t;p;"
于 2011-06-06T14:42:25.603 回答
3

使用 awk:

awk "BEGIN { o=\"\" }  { o=o \" \" \$0 }  END { print o; }"
于 2011-06-06T15:15:45.553 回答
3

我特别喜欢的一个解决方案是将所有文件附加到保留空间并替换文件末尾的所有换行符:

$ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}'
foobar

但是,有人说我在某些 sed 实现中保留空间可能是有限的。

于 2011-07-13T14:35:10.963 回答
3

用任何字符串替换换行符,并替换最后一个换行符

tr解决方案只能替换为单个字符,纯sed解决方案不会替换输入的最后一个换行符。以下解决方案修复了这些问题,并且对于二进制数据似乎是安全的(即使使用 UTF-8 语言环境):

printf '1\n2\n3\n' |
  sed 's/%/%p/g;s/@/%a/g' | tr '\n' @ | sed 's/@/<br>/g;s/%a/@/g;s/%p/%/g'

结果:

1<br>2<br>3<br>
于 2013-02-26T14:15:01.147 回答
3

在“正常”替换之后引入换行符的是sed 。首先,它修剪换行符,然后根据您的指示进行处理,然后引入换行符。

使用sed您可以在修剪后用您选择的字符串替换每个输入行的行的“结尾”(不是换行符);但是,sed会输出不同的行。例如,假设您想用“===”替换“行尾”(比用单个空格替换更通用):

PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF

first line===
second line===
3rd line===
PROMPT~$

要将换行符替换为字符串,您可以低效地使用tr,如前所述,将换行符替换为“特殊字符”,然后使用sed将该特殊字符替换为您想要的字符串.

例如:

PROMPT~$ cat <<EOF | tr '\n' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF

first line===second line===3rd line===PROMPT~$
于 2014-04-16T03:06:06.870 回答
3

另一种GNU方法,与 Zsolt Botykai的 answersed几乎相同,但它使用了不太常用的(音译)命令,该命令节省了一个字节的代码(尾随):sedyg

sed ':a;N;$!ba;y/\n/ /'

人们希望y运行速度比s, 快(也许速度tr快 20 倍),但在GNU sed v4.2.2 ys.


更便携的 BSD sed版本:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'
于 2016-07-02T22:22:57.250 回答
2
sed '1h;1!H;$!d
     x;s/\n/ /g' YourFile

这不适用于大文件(缓冲区限制),但如果有足够的内存来保存文件,它会非常有效。(更正H->1h;1!H在@hilojack 的好评之后)

另一个在读取时更改新行的版本(更多 cpu,更少内存)

 sed ':loop
 $! N
 s/\n/ /
 t loop' YourFile
于 2013-11-11T13:44:43.053 回答
2

这可能对您有用(GNU sed):

sed 'H;$!d;x;:a;s/^((.).*)\2/\1 /;ta;s/.//' file

H命令将换行符添加到模式空间,然后将结果附加到保留空间。sed 的正常流程是从每一行中删除以下换行符,因此这将在保留空间的开头引入一个换行符并复制文件的其余部分。一旦文件被放入保留空间,将保留空间与模式空间交换,然后使用模式匹配将所有原始换行符替换为空格。最后,删除引入的换行符。

这样做的好处是永远不会在 sed 命令中实际输入换行符。

选择:

sed 'H;$!d;x;y/\n/ /;s/.//' file

或者:

sed 'H;1h;$!d;x;y/\n/ /' file
于 2018-05-19T10:32:49.137 回答
2
cat file | xargs

为了完整起见

于 2021-11-11T21:44:55.823 回答
1

还有一个选择:

tr -s "[:space:]" " " < filename > filename2 && mv filename2 filename

用于tr -s

-s, --squeeze-repeats 将最后指定的 SET 中列出的重复字符的每个序列替换为该字符的一次出现

这使用单个空格替换文件中的所有空白序列,将结果写入新文件,然后将新文件重命名为原始名称。

于 2021-01-14T13:45:51.860 回答
0

@OP,如果你想替换文件中的换行符,你可以使用 dos2unix (或 unix2dox )

dos2unix yourfile yourfile
于 2009-08-10T00:49:14.660 回答
0

您还可以使用标准文本编辑器

printf '%s\n' '%s/$/ /' '%j' 'w' | ed -s file

注意:这会将结果保存回file.

sed这里的大多数答案一样,此解决方案必须首先将整个文件加载到内存中。

于 2016-11-03T19:32:06.683 回答
0

前面的大多数sed命令示例在我的 Unix 机器中对我不起作用,并给我错误消息:

Label too long: {:q;N;s/\n/ /g;t q}

这适用于所有 Unix/Linux 环境:

line=$(while read line; do echo -n "$line "; done < yoursourcefile.txt)
echo $line |sed 's/ //g' > sortedoutput.txt

第一行将从文件中删除所有新行yoursourcefile.txt并生成一行。第二个sed命令将删除其中的所有空格。

于 2018-03-19T15:20:34.847 回答
-1

这真的很简单......当我找到解决方案时,我真的很生气。又少了一个反斜杠。就是这个:

sed -i "s/\\\\\n//g" filename
于 2011-08-24T14:06:37.107 回答
-2

这里sed没有缓冲区(适合实时输出)。
示例:用\nHTML 中的<br/>break替换

echo -e "1\n2\n3" | sed 's/.*$/&<br\/>/'
于 2011-08-14T21:23:49.217 回答
-2

以下内容比大多数答案简单得多。此外,它正在工作:

echo `sed -e 's/$/\ |\ /g' file`
于 2012-05-16T16:35:40.367 回答
-3
sed -i ':a;N;$!ba;s/\n/,/g' test.txt

tr "\n" <file name>
于 2016-01-18T08:56:48.163 回答
-7

试试这个:

echo "a,b"|sed 's/,/\r\n/'
于 2010-12-14T14:53:50.927 回答
-7

在 sed 替换部分,键入反斜杠,按回车键转到第二行,然后以 /g' 结束:

sed 's/>/\
/g'

[root@localhost ~]# echo "1st</first>2nd</second>3rd</third>" | sed 's/>/\
> /g'
1st</first
2nd</second
3rd</third

[root@localhost ~]#
于 2012-09-17T15:54:07.323 回答