如何更换换行符(


How can I replace a newline (
) using sed?

如何使用sed命令替换换行符(

我尝试失败:

1
2
3
sed 's#
# #g' file
sed 's#^$# #g' file

我该怎么修?


tr代替?

1
2
tr '
' ' ' < input_filename

或者完全删除换行符:

1
2
tr -d '
' < input.txt > output.txt

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

1
2
tr --delete '
' < input.txt > output.txt


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

1
2
sed ':a;N;$!ba;s/
/ /g' file

这将在一个循环中读取整个文件,然后用空格替换换行符。

说明:

  • 通过:a创建标签。
  • 通过N将当前行和下一行附加到模式空间。
  • 如果我们在最后一行之前,那么分支到创建的标签$!ba($!)意味着不要在最后一行执行,因为应该有最后一行。
  • 最后,替换用模式空间(即整个文件)上的一个空间替换每个换行符。
  • 以下是与BSD和OS X的sed兼容的跨平台语法(根据@benjie comment):

    1
    2
    sed -e ':a' -e 'N' -e '$!ba' -e 's/
    / /g' file

    如您所见,使用sed解决这个简单的问题是有问题的。有关更简单和充分的解决方案,请参阅此答案。


    快速回答:

    1
    2
    sed ':a;N;$!ba;s/
    / /g' file
  • :a创建标签"a"
  • n将下一行附加到模式空间
  • $!如果不是最后一行,则BA分支(转到)标签为"A"
  • s substitute,//regex替换新行,//用空格,/g全局匹配(尽可能多次)
  • sed将循环执行步骤1到3,直到到达最后一行,使所有行都适合模式空间,其中sed将替换所有字符

    选择:

    与SED不同的是,所有备选方案都无需到达最后一行即可开始该过程。

    用重击,慢

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

    使用Perl、Sed-like速度

    1
    2
    perl -p -e 's/
    / /' file

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

    1
    2
    tr '
    ' ' ' < file

    使用粘贴,类似于tr的速度,只能替换为一个字符

    1
    paste -s -d ' ' file

    带awk,tr-like速度

    1
    awk 1 ORS=' ' file

    "echo$(

    SED常见问题5.10的长答案:

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

    将永远不匹配行尾的换行符,因为在将换行符放入图案空间。要将两条或多条线放入图案空间,请使用'n'命令或类似的命令(例如'h;…;g;')。

    塞德的作品是这样的:塞德一次读一行,删掉终止换行符,将剩余内容放入模式空间,SED脚本可以寻址或更改它,并且当模式空间是打印的,在stdout(或文件)上附加新行。如果模式空间全部或部分用"d"或"d"删除,在这种情况下不添加换行符。因此,脚本

    1
    2
    3
    4
    5
      sed 's/
    //' file       # to delete newlines from each line            
      sed 's/
    /foo
    /' file  # to add a word to the end of each line

    不会起作用,因为后面的换行符在线条被放入图案空间。要执行上述任务,使用以下脚本之一:

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

    因为除了GNU以外的其他版本的SED的大小限制为模式缓冲区,unix的"tr"实用程序在这里是首选的。如果文件的最后一行包含换行符,GNU SED将添加该换行到输出,但删除所有其他内容,而tr将删除所有换行。

    要匹配由两行或多行组成的块,有三个基本选项:(1)使用"n"命令将下一行添加到图案空间;(2)使用"h"命令至少两次以附加当前行到保留空间,然后从保留空间检索行对于X、G或G;或(3)使用地址范围(见上文第3.3节)匹配两个指定地址之间的行。

    选项(1)和(2)将在模式空间中放置一个可以根据需要编址("s/abcxyz/alphabet/g")。一个例子第4.13节中出现了使用"n"删除一个行块的方法。(如何删除特定连续行块?)这个示例可以通过将delete命令更改为否则,如"P"(打印)、"I"(插入)、"C"(更改)、"A"(附加),或"S"(替代)。

    选项(3)不会将放入模式空间,但会匹配一个连续的行块,因此可能不匹配甚至需要来查找您要查找的内容。自GNU SED以来版本3.02.80现在支持此语法:

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

    除了传统的"/from here/,/to there/…"范围之外地址,可能会完全避免使用。


    较短的awk替代方案:

    1
    awk 1 ORS=' '

    解释

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

    1
    condition { code-block }

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

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

    现在,在打印记录时,ORS(输出记录分隔符)会附加到该记录上,默认值又是一个换行符。因此,通过将ORS改为空间,所有新行都改为空间。


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

    1
    2
    sed -z 's/
    / /g'


    Perl版本的工作方式与您期望的一样。

    1
    2
    perl -i -p -e 's/
    //' file

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


    谁需要sed?这是bash路:

    1
    cat test.txt |  while read line; do echo -n"$line"; done


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

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

    如果您想要最后一行:

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

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

    1
    2
    awk '{printf"%s|", $0} END {printf"
    "}' inputfile


    1
    2
    tr '
    ' ' '

    是命令。

    简单易用。


    三件事。

  • 绝对不需要tr(或cat等)。(gnu)sed和(gnu)awk组合在一起时,可以完成99.9%的任何文本处理。

  • 流!=基于行。ed是一个基于行的编辑器。sed不是。有关差异的更多信息,请参阅SED讲座。大多数人将sed混淆为基于行,因为默认情况下,EDOCX1对简单匹配的模式匹配不是很贪婪——例如,当执行模式搜索并替换为一个或两个字符时,默认情况下,它只替换找到的第一个匹配(除非全局命令另有规定)。如果它是基于行而不是基于流的,那么甚至没有全局命令,因为它一次只计算行。试着运行ed;你会注意到区别。如果您想在特定的行上迭代(例如在for循环中),ed非常有用,但是大多数时候您只需要sed

  • 据说,

    1
    2
    sed -e '{:q;N;s/
    / /g;t q}' file

    在GNU sed版本4.2.1中工作正常。上面的命令将用空格替换所有换行符。打字很难看,也有点笨重,但效果很好。{}可以忽略不计,因为它们只是出于理智的原因才包括在内。


  • 答案是:一个标签…

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

    …在命令行的freebsd 7.2中不工作:

    1
    2
    3
    4
    5
    6
    7
    ( echo foo ; echo bar ) | sed ':a;N;$!ba;s/
    / /g'
    sed: 1:":a;N;$!ba;s/
    / /g": unused label 'a;N;$!ba;s/
    / /g'
    foo
    bar

    但是,如果您将SED脚本放在一个文件中,或者使用-e"构建"SED脚本…

    1
    2
    3
    > (echo foo; echo bar) | sed -e :a -e N -e '$!ba' -e 's/
    / /g'
    foo bar

    或者…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    > cat > x.sed << eof
    :a
    N
    $!ba
    s/
    / /g
    eof

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

    也许OSX中的SED是类似的。


    您可以使用xargs:

    1
    seq 10 | xargs

    1
    seq 10 | xargs echo -n


    易于理解的解决方案

    我有这个问题。更重要的是,我需要解决方案来处理BSD(Mac OS X)和GNU(Linux和Cygwin)的sedtr

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ echo 'foo
    bar
    baz


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

    输出:

    1
    2
    3
    foo
    bar
    baz

    (有尾随换行符)

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

  • 使用tr将换行符与另一个字符交换。

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

  • 使用sed匹配NULL

  • 如果需要,可以使用tr交换额外的换行符。


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

    The multiline Next (N) command creates a multiline pattern space by reading a new line of input and appending it to the contents of the pattern space. The original contents of pattern space and the new input line are separated by a newline. The embedded newline character can be matched in patterns by the escape sequence"
    ". In a multiline pattern space, the metacharacter"^" matches the very first character of the pattern space, and not the character(s) following any embedded newline(s). Similarly,"$" matches only the final newline in the pattern space, and not any embedded newline(s). After the Next command is executed, control is then passed to subsequent commands in the script.

    来自man sed

    [2addr]N

    Append the next line of input to the pattern space, using an embedded newline character to separate the appended material from the original contents. Note that the current line number changes.

    我用它来搜索(多个)格式不正确的日志文件,在这些文件中,搜索字符串可能在"孤立"的下一行中找到。


    为了响应上述"tr"解决方案,在Windows上(可能使用tr的gnuwin32版本),建议的解决方案:

    1
    2
    tr '
    ' ' ' < input

    不适用于我,它可能出错,或者由于某种原因实际替换了 w/""。

    使用tr的另一个特性,"删除"选项-d确实起作用,但是:

    1
    2
    tr -d '
    ' < input

    或"r"而不是"n"


    我使用了一种混合方法来绕过换行问题,使用tr将换行替换为制表符,然后用我想要的任何内容替换制表符。在本例中,""因为我正在尝试生成HTML分隔符。

    1
    2
    3
    4
    5
    echo -e"a
    b
    c
    " |tr '
    ' '\t' | sed 's/\t/  /g'`


    在某些情况下,您可以将RS更改为其他字符串或字符。这样,SUB/GSUB可以使用:

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

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

    关于呆呆的事情…把文件读到内存中,我不知道这一点,但对我来说,gawk似乎一次只处理一行,而且速度非常快(不像其他的一些那样快,但是写和测试的时间也很重要)。

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


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

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

    下面的解决方案避免了SED,而是将输入字节转换为八进制代码,然后再次转换为字节,但会截取八进制代码012(换行符),并输出替换字符串来代替它。据我所知,该解决方案是符合POSIX的,因此它应该在各种平台上工作。

    1
    2
    3
    4
    5
    od -A n -t o1 -v | tr ' \t' '

    ' | grep . |
      while read x; do ["0$x" -eq 012 ] && printf '
    ' || printf"\\$x"; done

    POSIX参考文档:嘘,shell命令语言,OD,TR,格雷普读,[打印。

    read[printf都是至少在bash中内置的,但这可能不是由posix保证的,因此在某些平台上,每个输入字节可能会启动一个或多个新进程,这将减慢速度。即使在bash中,这个解决方案也只能达到50kb/s左右,因此它不适用于大型文件。

    在Ubuntu(bash、dash和busybox)、freebsd和openbsd上测试。


    您可以使用xargs&mdash;默认情况下,它将用空格替换

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


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

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

    然而,有人说在某些SED实现中保留空间是有限的。


    在Mac OS X上(使用freebsd-sed):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # replace each newline with a space
    printf"a
    b
    c
    d
    e
    f" | sed -E -e :a -e '$!N; s/
    / /g; ta'
    printf"a
    b
    c
    d
    e
    f" | sed -E -e :a -e '$!N; s/
    / /g' -e ta


    使用awk:

    1
    awk"BEGIN { o="" }  { o=o " " \$0 }  END { print o; }"


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

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

    1
    2
    3
    4
    5
    6
    printf '1
    2
    3
    ' |
      sed 's/%/%p/g;s/@/%a/g' | tr '
    ' @ | sed 's/@//g;s/%a/@/g;s/%p/%/g'

    结果:

    1
    123


    在"正常"替换后引入新行的是SED。首先,它修剪新行字符,然后根据您的指示进行处理,然后引入新行。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    PROMPT~$ cat <<EOF |sed 's/$/===/g'
    first line
    second line
    3rd line
    EOF

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

    要用字符串替换新行字符,您可以使用tr(如前所述)将新行字符替换为"特殊字符",然后使用sed将该特殊字符替换为所需的字符串。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    PROMPT~$ cat <<EOF | tr '
    ' $'\x01'|sed -e 's/\x01/===/g'
    first line
    second line
    3rd line
    EOF

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


    删除空行:

    1
    sed -n"s/^$//;t;p;"


    另一个gnu sed方法,几乎与zsolt botykai的答案相同,但它使用了sed较不常用的y命令(transliterate),这节省了一个字节的代码(后面的G

    1
    2
    sed ':a;N;$!ba;y/
    / /'

    人们希望y的运行速度比s快(可能是tr的速度快20倍),但在GNU SED v4.2.2中,ys慢4%。

    更便携的BSD sed版本:

    1
    2
    sed -e ':a' -e 'N;$!ba' -e 'y/
    / /'


    你也可以用这个方法

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

    解释

    1
    2
    3
    4
    5
    6
    7
    8
    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
     is
          available in pattern space.
    $!d - Clear the pattern space every time before getting next line until the
          last line.

    Flow:当第一行从输入中获取时,进行交换,因此1转到保留空间,然后转到模式空间,然后将保留空间追加到模式空间,然后执行替换并删除模式空间。在进行第二行交换时,2到保持空间,1到图案空间,然后G将保持空间追加到图案空间,然后h将图案复制到图案空间,进行替换并删除。此操作将继续,直到达到EOF,然后打印准确的结果。


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

    1
    2
    3
    tr '[

    ]' ' ' < $input > $output


    @op,如果要替换文件中的换行符,只需使用dos2unix(或unix2dox)

    1
    dos2unix yourfile yourfile


    1
    2
    3
    sed '1h;1!H;$!d
         x;s/
    / /g' YourFile

    这不适用于大型文件(缓冲区限制),但如果有足够的内存来保存文件,则效率非常高。(修正H->1h;1!H,经过@hilojack的好评)

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

    1
    2
    3
    4
    5
     sed ':loop
     $! N
     s/
    / /
     t loop' YourFile


    使用allowing查找和替换

    1
    2
    3
    4
    sed -ie -z 's/Marker
    /# Marker Comment
    Marker
    /g' myfile.txt

    Marker

    变成

    # Marker Comment

    Marker


    我发布这个答案是因为我尝试过上面提供的大多数sed推荐示例,这些示例在我的Unix系统中不起作用,并且给了我错误消息Label too long: {:q;N;s/
    / /g;t q}
    。最后,我提出了我的要求,并在此共享了适用于所有UNIX/Linux环境的内容:

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

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


    这可能适用于您(GNU SED):

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

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

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


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

    1
    2
    3
    4
    printf '%s
    %s
    %s
    ' '%s/$/ /' '%j' 'w' | ed -s file

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

    sed一样,此解决方案也会遇到先将整个文件加载到内存中的问题。


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

    1
    2
    sed -i"s/\\\\
    //g" filename


    我认为最简单和最快的方法是使用grep。在regexp egrep或aka grep -E中使用grep有一个捷径,所以我们要做的只是

    1
    egrep '^\S.+' fileNameWithUnneededNewLines > ClearedFile


    这里是没有缓冲区的sed(对于实时输出很好)。示例:用HTML中的
    break替换

    1
    2
    3
    echo -e"1
    2
    3" | sed 's/.*$/&<br\/>/'


    以下内容比大多数答案简单得多。同时,它也起作用:

    1
    echo `sed -e 's/$/\ |\ /g' file`


    1
    2
    3
    4
    5
    sed -i ':a;N;$!ba;s/
    /,/g' test.txt

    tr"
    " <file name>

    试试这个:

    1
    2
    3
    echo"a,b"|sed 's/,/

    /'


    在SED替换部件中,键入反斜杠,按Enter键转到第二行,然后以/g'结束:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    sed 's/>/\
    /g'

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

    [root@localhost ~]#