如何使用tr(1)从非空行删除换行符('\ n',0x0A)?

时间:2011-11-18 05:40:59

标签: perl bash sed tr

我有一个名为 file1 的文件,其中包含以下内容:

The answer t
o your question 

A conclusive a
nswer isn’t al
ways possible.

When in doubt, ask pe
ople to cite their so
urces, or to explain

Even if we don’t agre
e with you, or tell y
ou.

我想将 file1 转换为 file2 。后者应如下所示:

The answer to your question

A conclusive answer isn’t always possible.

When in doubt, ask people to cite their sources, or to explain

Even if we don’t agree with you, or tell you.

如果我只是执行cat file1 | tr -d "\n" > file2",则会删除所有换行符字符。何时只删除使用tr(1)实用程序在非空行上的换行符字符?

6 个答案:

答案 0 :(得分:9)

perl -00 -lpe 'tr/\n//d'

-00是Perl的“段落”模式,用一个或多个空行作为分隔符读取输入。 -l将系统换行符附加到print命令,因此删除输入中的所有换行符是安全的。

答案 1 :(得分:3)

tr无法执行此操作,但sed可以轻松

sed -ne '$!H;/^$/{x;s/\n//g;G;p;d;}' file1 > file2

这会找到非空行并保留它们。然后,在空行上,它从保留的数据中删除换行符并打印结果,后跟换行符。删除保留的数据并重复该过程。

编辑:

Per @ potong的评论,这是一个版本,在文件的末尾不需要额外的空行。

sed -ne 'H;/^$/{x;s/\n//g;G;p;};${x;s/\n//g;x;g;p;}' file1 > file2

答案 2 :(得分:2)

如果您认识的某个角色没有出现在您的输入中,您可以执行以下操作:

# Assume that the input doesn't contain the '|' character at all
tr '\n' '|' < file1 | sed 's/\([^|]\)|\([^|]\)/\1\2/g' | tr '|' '\n' > file2

用替换字符|替换所有换行符; sed然后删除在其他角色之前和之后的所有|实例;最后,它用换行符替换|

答案 3 :(得分:2)

这可能对您有用:

# sed '1{h;d};H;${x;s/\([^\n]\)\n\([^\n]\)/\1\2/g;p};d' file

The answer to your question 

A conclusive answer isn't always possible.

When in doubt, ask people to cite their sources, or to explain

Even if we don't agree with you, or tell you.

答案 4 :(得分:2)

file1中的换行符分为四类:

  1. 换行符后跟另一个换行符
  2. newline以换行符开头
  3. 文件末尾的换行符
  4. 夹心换行
  5. 通过阅读整个输入(-000选项)删除第一个类,并在每个地方替换一个换行符,我们看到一对(s/\n\n/\n/g)让我们

    $ perl -000 -pe 's/\n\n/\n/g' file1 
    The answer t
    o your question 
    A conclusive a
    nswer isn’t al
    ways possible.
    When in doubt, ask pe
    ople to cite their so
    urces, or to explain
    Even if we don’t agre
    e with you, or tell y
    ou.

    这不是我们想要的,因为第一类换行应终止file2中的行。

    我们可能会尝试聪明并使用负面后视来删除前面有其他换行符(第二类)的换行符,但输出与前一种情况无法区分,这是有道理的,因为这次我们删除了后者而不是前者在每个相邻的新线中。

    $ perl -000 -pe 's/(?<=\n)\n//g' file1 
    The answer t
    o your question 
    A conclusive a
    nswer isn’t al
    ways possible.
    When in doubt, ask pe
    ople to cite their so
    urces, or to explain
    Even if we don’t agre
    e with you, or tell y
    ou.

    即便如此,这仍然不是我们想要的,因为其他新行的前面的成为file2中的空行。

    很明显,我们希望在file1结束时继续使用换行符。

    我们想要的是一个只删除第四个类的程序:每个换行符之前没有另一个换行符,后面跟着另一个换行符和逻辑输入结束符。

    使用Perl's look-around assertions,规范很简单,虽然外观可能有点令人生畏。 “没有换行符”是负面的后瞻(?<!\n)。使用否定前瞻(?!...)我们不希望看到另一个换行符或(|)输入的结尾($)。

    把它们放在一起我们得到了

    $ perl -000 -pe 's/(?<!\n)\n(?!\n|$)//g' file1 
    The answer to your question
    
    A conclusive answer isn’t always possible.
    
    When in doubt, ask people to cite their sources, or to explain
    
    Even if we don’t agree with you, or tell you.

    最后,要创建file2,请重定向标准输出。

    perl -000 -pe 's/(?<!\n)\n(?!\n|$)//g' file1  >file2

答案 5 :(得分:0)

你不能单独使用trtr非常方便,但严格来说是char-by-char过滤器,没有前瞻或后视。

您可以使用sed获取示例输出,但这真的很痛苦(我想!)。 编辑(sed master @Sorpigal证明我错了!)

以下是awk

的解决方案
/home/shellter:>cat <<-EOS \
| awk 'BEGIN{RS="\n\n"}; { gsub("\n", "", $0) ;printf("%s %s", $0, "\n\n") }'
The answer t
o your question 

A conclusive a
nswer isn’t al
ways possible.

When in doubt, ask pe
ople to cite their so
urces, or to explain

Even if we don’t agre
e with you, or tell y
ou.
EOS


# output
The answer to your question

A conclusive answer isnt always possible.

When in doubt, ask people to cite their sources, or to explain

Even if we dont agree with you, or tell you.

很奇怪,它显示为三倍间距,但它实际上是间隔的。

Awk有为每个文件填充的预定义变量,以及它读取的每行文本,即

RS = RecordSeperator -- normally a line of data, but a configurable value, that when set 
                     to '\n\n' means a blank line, or a typical separation on a paragraph

$0 = complete line of text (as defined by the internal variables RS (RecordSeparator)
                             In this problem, it is each paragraph of data, viewed though
                             as a record.

$1 = first field in text (as defined by the internal variables FS (FieldSeparator)
                           which defaults to (possibly multiple) space chars OR tab char
                          a line with 2 connected spaces chars and 1 tab char has 3 fields)

NF = Number(of)Fields in current line of data (again fields defined by value of FS as 
                                                described above)

(there are many others, besides, $0, $n, $NF, $FS, $RS).

你可以通过在示例代码中使用变量来编程增加$ 1,$ 2,$ 3等值,例如$ i(i是一个介于2和NF之间的数字的变量。前导'$' 说给我字段i的价值(即2美元,3美元,4美元......)

我希望这会有所帮助。