我试过了:
sed -i 's/\n+/\n/' file
但它不起作用。
我仍然想要单线换行。
输入:
abc
def
ghi
jkl
期望的输出:
abc
def
ghi
jkl
答案 0 :(得分:3)
Sed不太擅长以编程方式检查多行的任务。这是我能得到的最接近的:
$ sed '/^$/{n;/^$/d}' file
abc
def
ghi
jkl
这个逻辑:如果你找到一个空行,请看下一行。如果下一行也是空白,则删除下一行。
这不会吞噬所有的行,因为它假设有一个有意的额外对,并将两个\n\n
减少到两个\n
。
在基本awk
中执行此操作:
$ awk 'NF > 0 {blank=0} NF == 0 {blank++} blank < 2' file
abc
def
ghi
jkl
这使用一个名为 blank 的变量,当字段数(NF
)非零时为零,当它们为零(空白行)时递增。当连续空白行数小于2时,执行Awk的默认操作打印。
答案 1 :(得分:1)
使用awk(gnu或BSD)可以:
awk -v RS= -v ORS='\n\n' '1' file
abc
def
ghi
jkl
还使用perl
:
perl -pe '$/=""; s/(\n)+/$1$1/' file
abc
def
ghi
jkl
答案 2 :(得分:1)
perl -00 -pe 1 filename
将输入文件拆分为由2个或更多换行符分隔的“段落”,然后打印由单个空行分隔的段落:
perl -00 -pe 1 <<END
abc
def
ghi
jkl
END
abc
def
ghi
jkl
答案 3 :(得分:0)
这可能适合你(GNU sed):
sed '/^$/{:a;N;s/\n$//;ta}' file
这会用一个空行替换多个空白行。
但是,如果您想在每个非空白行后面放置一个空行,那么:
sed '/^$/d;G' file
删除所有空白行,只将一个空白行附加到非空白行。
答案 4 :(得分:0)
在这里找到That's What I Sed(破坏者:比this solution慢)。
sed '/^$/N;/\n$/D' file
sed
脚本的内容如下:
如果下一行为空,请删除当前行。
并且可以转换为以下伪代码:
1 | # sed '/^$/N;/\n$/D' file
2 | while not end of file :
3 | buffer = next line
4 | # /^$/N
5 | if buffer is empty : # /^$/
6 | buffer += "\n" + next line # N
7 | end if
8 | # /\n$/D
9 | if buffer ends with "\n" : # /\n$/
10 | delete first line in buffer and go to 5 # D
11 | end if
12 | print buffer
13 | end while
在正则表达式/^$/
中,^
和$
分别表示“缓冲区开始”和“缓冲区结束”。它们指的是缓冲区的边缘,而不是缓冲区的内容。
D
命令执行以下任务:如果缓冲区包含换行符,则删除缓冲区的文本,直到第一个换行符,然后重新启动程序循环而不处理其余命令,而无需打印缓冲区,而无需读取新的输入行。
最后,请记住,sed
会在处理行之前删除尾随的换行符。因此,在上面的代码中,如果下一行是Hello World!\n
,则next line
隐式引用Hello World!
。还应考虑print
重新添加尾随换行符。
更多详情,请访问https://www.gnu.org/software/sed/manual/sed.html。
您现在可以尝试使用包含以下内容的文件了:
a\n
b\n
\n
\n
\n
c\n
好的,现在让我们看看为什么this solution更快。
sed
脚本/^$/{:a;N;s/\n$//;ta}
的读法如下:
如果当前行与
/^$/
相匹配,则执行{:a;N;s/\n$//;ta}
。
由于^
和$
之间没有任何内容,因此我们可以这样改写:
如果当前行为空,则执行
{:a;N;s/\n$//;ta}
。
这意味着sed
为每个空行执行以下命令:
步骤 | 命令 | 说明 |
---|---|---|
1 | :a |
声明一个名为“ a”的标签。 |
2 | N |
在下一行前面加上换行符(\n )到当前行。 |
3 | s/\n$// |
用任何结尾的换行符(s )代替(/\n$/ ),不要包含任何内容(// )。 |
4 | ta |
如果执行了替换(在步骤3),则返回到标签“ a”(在步骤1),否则打印结果并移至下一行。 |
非空行仅按原样打印。知道了所有这些,我们可以使用以下伪代码描述整个过程:
1 | # sed '/^$/{:a;N;s/\n$//;ta}' file
2 | while not end of file :
3 | buffer = next line
4 | # /^$/{:a;N;s/\n$//;ta}
5 | if buffer is empty : # /^$/
6 | :a # :a
7 | buffer += "\n" + next line # N
8 | if buffer ends with "\n" : # /\n$/
9 | remove last "\n" from buffer # s/\n$//
10 | go to :a (at 6) # ta
11 | end if
12 | end if
13 | print buffer
14 | end while
如您所见,两个sed
脚本非常相似。实际上,s/\n$//;ta
与/\n$/D
几乎相同。但是,第二个脚本跳过了第5步,因此它比第一个脚本更快。让这两个脚本的时间都填满〜10Mb的空行:
$ yes '' | head -10000000 > file
$ /usr/bin/time -f%U sed '/^$/N;/\n$/D' file > /dev/null
3.61
$ /usr/bin/time -f%U sed '/^$/{:a;N;s/\n$//;ta}' file > /dev/null
2.37
第二个脚本获胜。
答案 5 :(得分:-1)
为什么不删除所有空白行,然后在每行后添加一个空白行?对于您指定的输入文件tmp
,
sed '/^$/d' tmp|sed '0~1 a\ '
abc
def
ghi
jkl
如果空格(空格和制表符)计为&#34;空白&#34;为您排队,然后使用sed '/^\s*$/d' tmp|sed '0~1 a\ '
代替。
请注意,这些解决方案最后会留下一个尾随空白行,因为我不确定是否需要这样做。轻松删除。
答案 6 :(得分:-1)
这为您提供了仅使用sed所需的内容:
sed '/^$/d' txt | sed -e $'s/$/\\\n/'
第一个sed命令删除所有空行,表示为&#34; ^ $&#34;。
第二个sed命令在每一行的末尾插入一个换行符。