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

时间:2009-08-09 19:10:10

标签: sed

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

我没试成功:

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

我该如何解决?

43 个答案:

答案 0 :(得分:1560)

改为使用tr

tr '\n' ' ' < input_filename

或完全删除换行符:

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

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

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

答案 1 :(得分:1378)

将此解决方案与GNU sed

一起使用
sed ':a;N;$!ba;s/\n/ /g' file

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

说明:

  1. 通过:a创建标签。
  2. 通过N将当前和下一行附加到模式空间。
  3. 如果我们在最后一行之前,请转移到创建的标签$!ba$!表示不在最后一行执行,因为应该有一个最终换行符。)
  4. 最后,替换用模式空间(即整个文件)上的空格替换每个换行符。
  5. 这是跨平台兼容的语法,适用于BSD和OS X的sed(根据@Benjie comment):

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

    正如您所看到的,使用sed来解决这个简单的问题是有问题的。有关更简单和充分的解决方案,请参阅this answer

答案 2 :(得分:445)

快速回答:

sed ':a;N;$!ba;s/\n/ /g' file
  1. 创建标签'a'
  2. N 将下一行追加到模式空间
  3. $! 如果不是最后一行 ba 分支(转到)标签'a' < / LI>
  4. s 替换 / \ n / 正则表达式换行 / / 按空格 / g 全局匹配(尽可能多次)
  5. sed将循环执行步骤1到3,直到它到达最后一行,让所有行都适合模式空间,其中sed将替换所有\ n个字符


    <强>替代

    sed 不同,所有替代方案都不需要到达最后一行开始流程

    bash ,慢

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

    perl sed 式速度

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

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

    tr '\n' ' ' < file
    

    粘贴 tr 式速度,只能替换为一个字符

    paste -s -d ' ' file
    

    awk tr -like speed

    awk 1 ORS=' ' file
    

    “echo $(&lt; file)”之类的其他选择很慢,仅适用于小文件,需要处理整个文件才能开始此过程。


    来自sed FAQ 5.10

    长答案

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

    \ n将永远不会匹配行尾的换行符,因为    在将线放入
    中之前,新线始终被剥离    模式空间。要在模式空间中获得2行或更多行,请使用
       'N'命令或类似的东西(例如'H; ...; g;')。

    Sed的工作原理如下:sed一次读取一行,然后切掉    终止换行符,将剩下的内容放入模式空间中    sed脚本可以解决或更改它,以及当模式空间
    时    打印后,在stdout(或文件)中附加换行符。如果是    用'd'或'D'完全或部分删除模式空间    在这种情况下,换行符 not 。因此,像

    这样的脚本
      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'命令将Next行添加到模式空间;
       (2)使用'H'命令至少两次附加当前行
       到保留空间,然后从保持空间中检索线    用x,g或G;或(3)使用地址范围(见上文第3.3节)
       匹配两个指定地址之间的行。

    选择(1)和(2)将\ n放入模式空间,其中为
       可以根据需要进行寻址('s / ABC \ nXYZ / alphabet / g')。一个例子
       使用'N'删除一个行块出现在4.13章中    (“如何删除特定连续行的块?”)。这
       可以通过将delete命令更改为某些内容来修改示例    否则,如'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。

答案 3 :(得分:203)

更短的awk替代方案:

awk 1 ORS=' '

解释

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

condition { code-block }

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

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

现在,在打印记录时,会附加ORS(输出记录分隔符),默认值也是换行符。因此,通过将ORS更改为空格,所有换行都将更改为空格。

答案 4 :(得分:81)

Perl版本的工作方式符合预期。

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

正如评论中所指出的,值得注意的是,这种编辑已经到位。如果您的regular expression不像您想象的那么聪明,-i.bak会在替换之前为您提供原始文件的备份。

答案 5 :(得分:42)

谁需要sed?这是bash方式:

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

答案 6 :(得分:24)

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

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

如果您想要最终换行符:

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

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

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

答案 7 :(得分:20)

tr '\n' ' ' 

是命令。

简单易用。

答案 8 :(得分:20)

三件事。

    绝对不需要
  1. tr(或cat等)。 (GNU)sed和(GNU)awk合并后,可以完成所需文本处理的99.9%。

  2. stream!=基于行。 ed是一个基于行的编辑器。 sed不是。有关差异的更多信息,请参阅sed lecture。大多数人将sed混淆为基于行的,因为默认情况下,它在SIMPLE匹配的模式匹配中并不是非常贪婪 - 例如,在进行模式搜索并替换一个或两个字符时,默认情况下它只是替换它找到的第一个匹配项(除非global命令另有指定)。如果它是基于行的而不是基于STREAM的,那么甚至不会有全局命令,因为它一次只评估行。尝试运行ed;你会发现差异。 ed非常有用,如果你想迭代特定的行(例如在for循环中),但大多数时候你只想要sed

  3. 话虽如此,

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

    在GNU sed版本4.2.1中工作得很好。上面的命令将用空格替换所有换行符。输入它很难看并且有点麻烦,但它工作得很好。可以省略{},因为它们仅出于理智原因而被包含在内。

答案 9 :(得分:12)

答案:标签......

How can I replace a newline (\n) using sed?

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

( echo foo ; echo bar ) | sed ':a;N;$!ba;s/\n/ /g'
sed: 1: ":a;N;$!ba;s/\n/ /g": unused label 'a;N;$!ba;s/\n/ /g'
foo
bar

但是如果你把sed脚本放在一个文件中或使用-e来“构建”sed脚本......

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

或......

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

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

也许OS X中的sed类似。

答案 10 :(得分:10)

您可以使用xargs

seq 10 | xargs

seq 10 | xargs echo -n

答案 11 :(得分:10)

为什么我找不到awk的简单解决方案?

awk '{printf $0}' file

printf将打印每行而不包含换行符,如果您想用空格或其他分隔原始行:

awk '{printf $0 " "}' file

答案 12 :(得分:10)

易于理解的解决方案

我有这个问题。问题是我需要解决方案来处理BSD(Mac OS X)和GNU(Linux和Cygwinsedtr

$ 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换回额外的换行符

答案 13 :(得分:9)

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

  

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

来自man sed

  

[2addr] n的

     

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

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

答案 14 :(得分:6)

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

tr '\n' ' ' < input

对我来说不起作用,出于某种原因它要么出错,要么实际取代\ n w /''。

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

tr -d '\n' < input

或'\ r \ n'代替'\ n'

答案 15 :(得分:6)

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

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`

答案 16 :(得分:5)

防弹解决方案。二进制数据安全和POSIX兼容,但速度慢。

POSIX sed 需要输入根据 POSIX text filePOSIX line 定义,所以不允许使用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 command languageodtrgrepread[printf

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

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

答案 17 :(得分:5)

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

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

shell脚本的强大之处在于,如果您不知道如何以某种方式执行此操作,则可以通过其他方式执行此操作。很多时候,你需要考虑更多的事情,而不是在一个简单的问题上做出复杂的解决方案。

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

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

答案 18 :(得分:4)

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

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

答案 19 :(得分:3)

sed 在&#34; normal&#34;之后引入新行。代换。首先,它修剪新行字符,然后根据您的指示处理,然后引入一个新行。

使用 sed ,您可以替换&#34;结束&#34;修剪后的行(不是新行字符),每个输入行都有一个您选择的字符串;但是, sed 会输出不同的行。例如,假设您想要替换&#34;行结束&#34;用&#34; ===&#34; (比用单个空格替换更常见):

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

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

要使用字符串替换换行字符,您可以使用 tr ,如前所述,使用&#34;特殊字符替换newline-chars&#34 ;然后使用 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~$

答案 20 :(得分: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

答案 21 :(得分: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>

答案 22 :(得分:3)

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

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

然而,有人说我在一些sed实现中保持空间可能是有限的。

答案 23 :(得分:3)

使用Awk:

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

答案 24 :(得分:3)

删除空行:

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

答案 25 :(得分:2)

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

dos2unix yourfile yourfile

答案 26 :(得分:2)

您也可以使用此方法

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 next line until the
      last line.

流速:
   当第一行从输入获得时,进行交换,因此1进入保持空间并且\ n进入模式空间,然后将保留空间附加到模式空间,然后执行替换并删除模式空间。
   在第二行交换期间,2进入保持空间,1进入模式空间,然后G将保留空间附加到模式空间,然后h将模式复制到模式空间并进行替换并删除。此操作一直持续到达到eof,然后打印出准确的结果。

答案 27 :(得分:2)

另一种 GNU sed方法,与Zsolt Botykai's answer几乎相同,但这使用sed经常使用较少的y }(音译)命令,保存一个字节的代码(尾随g):

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

有人希望y的运行速度比s快,(可能速度为tr,速度提高20倍),但 GNU sed v4.2.2 { {1}}比<{1}}慢<4> 。

更便携 BSD y版本:

s

答案 28 :(得分:1)

使用\ n

查找和替换
import React, { Component } from 'react';
import {
  Link,
  withRouter,
} from 'react-router-dom';

import { auth } from '../../firebase';
import * as routes from '../../constants/routes';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import {signup} from './../../actions/signup';

const SignUpPage = ({ history }) =>
  <div>
    <h1>SignUp</h1>
    <SignUpForm history={history} />
  </div>

const updateByPropertyName = (propertyName, value) => () => ({
  [propertyName]: value,
});

const INITIAL_STATE = {
  username: '',
  email: '',
  passwordOne: '',
  passwordTwo: '',
  error: null,
};

class SignUpForm extends Component {
  constructor(props) {
    super(props);

    this.state = { ...INITIAL_STATE };
  }

  onSubmit = (event) => {
    const {
      username,
      email,
      passwordOne,
    } = this.state;

    const {
      history,
    } = this.props;

    auth.doCreateUserWithEmailAndPassword(email, passwordOne)
      .then(authUser => {
        const userid = authUser.user.uid;
        const user = { email, userid };
        this.props.signup(user);

      })
      .catch(error => {
        this.setState(updateByPropertyName('error', error));
      });

    event.preventDefault();
  }

  render() {
    const {
      username,
      email,
      passwordOne,
      passwordTwo,
      error,
    } = this.state;

    const isInvalid =
      passwordOne !== passwordTwo ||
      passwordOne === '' ||
      username === '' ||
      email === '';

    return (
      <form onSubmit={this.onSubmit}>
        <input
          value={username}
          onChange={event => this.setState(updateByPropertyName('username', event.target.value))}
          type="text"
          placeholder="Full Name"
        />
        <input
          value={email}
          onChange={event => this.setState(updateByPropertyName('email', event.target.value))}
          type="text"
          placeholder="Email Address"
        />
        <input
          value={passwordOne}
          onChange={event => this.setState(updateByPropertyName('passwordOne', event.target.value))}
          type="password"
          placeholder="Password"
        />
        <input
          value={passwordTwo}
          onChange={event => this.setState(updateByPropertyName('passwordTwo', event.target.value))}
          type="password"
          placeholder="Confirm Password"
        />
        <button disabled={isInvalid} type="submit">
          Sign Up
        </button>

        { error && <p>{error.message}</p> }
      </form>
    );
  }
}

const SignUpLink = () =>
  <p>
    Don't have an account?
    {' '}
    <Link to={routes.SIGN_UP}>Sign Up</Link>
  </p>

const mapDispatchToProps = dispatch => bindActionCreators({ signup }, dispatch)

export default connect(null, mapDispatchToProps)(withRouter(SignUpPage));

export {
  SignUpForm,
  SignUpLink,
};
  

标记

成为

  

#个标记注释

     

标记

答案 29 :(得分:1)

另一种选择:

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

tr -s 的用途:

<块引用>

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

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

答案 30 :(得分:1)

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

tr '[\r\n]' ' ' < $input > $output

答案 31 :(得分:1)

我来这里学习的是如何删除文件中的所有空白行。为此

 sed "/^\s*$/ d" fileName

答案 32 :(得分:1)

我发布了这个答案,因为我已尝试使用上面提供的大多数cf <- tibble(x = seq(0,pi,0.1), y = abs(cos(x))) xlim <- cf %>% filter(y < 0.5) %>% arrange(desc(y)) %>% top_n(1) %>% select(x) ggplot(cf, aes(x, y) ) + geom_point(size = 1, colour = "blue") + geom_hline(colour = "red", size = 1.2, yintercept = 0.5) + geom_vline(colour = "#99CCFF", size = 1, xintercept = as.numeric(xlim[1])) + labs(title = paste0("Y < 0.5 for X > ", as.numeric(xlim[1]))) 推荐示例,这在我的Unix框中对我不起作用并给我错误消息sed。最后我提出了我的要求,因此在这里分享了适用于所有Unix / Linux环境: -

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

第一行将从文件line=$(while read line; do echo -n "$line "; done < yoursourcefile.txt) echo $line |sed 's/ //g' > sortedoutput.txt 中删除所有新行,并生成一行。第二个yoursourcefile.txt命令将删除它的所有空格。

答案 33 :(得分:1)

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

这对于大文件(缓冲区限制)不起作用,但如果有足够的内存来保存文件,则效率非常高。 (@hilojack的好评后更正H - &gt; 1h;1!H

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

 sed ':loop
 $! N
 s/\n/ /
 t loop' YourFile

答案 34 :(得分:0)

您还可以使用Standard Text Editor

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

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

sed一样,此解决方案必须首先将整个文件加载到内存中。

答案 35 :(得分:0)

这可能适合你(GNU sed):

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

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

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

答案 36 :(得分:-1)

我认为最简单,最快捷的方法就是使用grep将grep与regexp egrep又名grep -E一起使用,所以我们要做的就是

egrep '^\S.+' fileNameWithUnneededNewLines > ClearedFile

答案 37 :(得分:-1)

这很简单......当我找到解决方案时,我真的很烦。只剩下一个反斜杠了。就是这样:

sed -i "s/\\\\\n//g" filename

答案 38 :(得分:-2)

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

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

答案 39 :(得分:-2)

这里是sed没有缓冲区(适合实时输出) 示例:将\n替换为HTML中的<br/>中断

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

答案 40 :(得分:-3)

sed -i ':a;N;$!ba;s/\n/,/g' test.txt

tr "\n" <file name>

答案 41 :(得分:-6)

试试这个:

echo "a,b"|sed 's/,/\r\n/'

答案 42 :(得分:-7)

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

sed 's/>/\
/g'

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

[root@localhost ~]#