使用sed,awk,tr和friends删除尾随/开始换行符

ELL*_*BLE 37 unix awk sed tr

我想从文件中删除所有空行,但只有当它们位于文件的结尾/开始时(即,如果它们之前没有非空行,则在开始时;如果有最后没有非空行.)

这是否可能在Perl或Ruby等功能齐全的脚本语言之外?我宁愿用做这个sed或者awk如果可能的话.基本上,任何轻量级和广泛使用的UNIX-y工具都可以,特别是我可以快速了解更多(Perl,因此,不包括在内).

dog*_*ane 51

来自sed的有用单行脚本:

# Delete all leading blank lines at top of file (only).
sed '/./,$!d' file

# Delete all trailing blank lines at end of file (only).
sed -e :a -e '/^\n*$/{$d;N;};/\n$/ba' file
Run Code Online (Sandbox Code Playgroud)

因此,要从文件中删除前导和尾随空行,可以将上述命令组合到:

sed -e :a -e '/./,$!d;/^\n*$/{$d;N;};/\n$/ba' file
Run Code Online (Sandbox Code Playgroud)

  • 根据该站点上的注释,尾行脚本不适用于gsed 3.02。*。这将起作用:`sed -e:a -e'/ ^ \ n * $ / {$ d; N; ba'-e'}'` (2认同)

Izk*_*ata 10

因此,我将借用@ dogbane的部分答案,因为sed删除前导空白行的那一行很短...

tac是coreutils的一部分,并反转文件.所以做两次:

tac file | sed -e '/./,$!d' | tac | sed -e '/./,$!d'
Run Code Online (Sandbox Code Playgroud)

它当然不是最有效的,但除非你需要效率,否则我发现它比其他任何东西都更具可读性.


Jas*_*oss 7

正如另一个答案中提到的,tac是 coreutils 的一部分,并反转文件。将执行两次的想法与命令替换将删除尾随新行的事实相结合,我们得到

echo "$(echo "$(tac "$filename")" | tac)"
Run Code Online (Sandbox Code Playgroud)

这不取决于sed. 您可以使用它echo -n来去除剩余的尾随换行符。

  • +1(相对)简单性(尽管以牺牲效率为代价);OSX 版本(默认情况下 `tac` 不可用):`echo "$(echo "$(tail -r "$filename")" | tail -r)"` 我运行了测试来比较相对执行速度与 1 - 数个答案的百万行文件(没有注意内存使用);较早意味着更快: OSX 10.10: sed (dogbane) < bash (mklement0) < awk (glenn jackman) < tac (tail -r; you) Ubuntu 14.04: sed (dogbane) < tac (you) < bash (mklement0) < awk (glenn jackman) 一个有趣的区别是 `tac` 在 Ubuntu 上比在 OSX 上快得多。 (2认同)
  • 有一个边缘情况值得一提:如果文件没有尾随 `\n`,则最后一行将无法正确处理:尝试 `echo "$(echo "$(printf 'a\nb' | tac) “ | tac)”`。这是“tac”(以及 OSX 上的“tail -r”)的固有行为(可以说是有缺陷的),输入不以“\n”结尾。 (2认同)

gle*_*man 6

这是 awk 中的一次性解决方案:它在看到非空行之前不会开始打印,当看到空行时,它会记住它直到下一个非空行

awk '
    /[[:graph:]]/ {
        # a non-empty line
        # set the flag to begin printing lines
        p=1      
        # print the accumulated "interior" empty lines 
        for (i=1; i<=n; i++) print ""
        n=0
        # then print this line
        print
    }
    p && /^[[:space:]]*$/ {
        # a potentially "interior" empty line. remember it.
        n++
    }
' filename
Run Code Online (Sandbox Code Playgroud)

请注意,由于我用来考虑空行/非空行(带有[[:graph:]]/^[[:space:]]*$/)的机制,只有空格的内部行将被截断为真正的空行。


Aur*_*gas 5

这是一个经过修改的 sed 版本,它也将那些只有空格和制表符的行视为“空”。

\n\n
sed -e :a -e \'/[^[:blank:]]/,$!d; /^[[:space:]]*$/{ $d; N; ba\' -e \'}\'\n
Run Code Online (Sandbox Code Playgroud)\n\n

它基本上是接受的答案版本(考虑 BryanH 评论),但.第一个命令中的点已更改为[^[:blank:]](任何非空白的内容),\\n第二个命令地址内部已更改为[[:space:]]允许换行符、空格和制表符。

\n\n

替代版本,不使用 POSIX 类,但您的 sed 必须支持\\t在. GNU sed 可以,BSD sed 不能。\\n[\xe2\x80\xa6]

\n\n
sed -e :a -e \'/[^\\t ]/,$!d; /^[\\n\\t ]*$/{ $d; N; ba\' -e \'}\'\n
Run Code Online (Sandbox Code Playgroud)\n\n

测试:

\n\n
prompt$ printf \'\\n \\t \\n\\nfoo\\n\\nfoo\\n\\n \\t \\n\\n\' \n\n\n\nfoo\n\nfoo\n\n\n\nprompt$ printf \'\\n \\t \\n\\nfoo\\n\\nfoo\\n\\n \\t \\n\\n\' | sed -n l\n$\n \\t $\n$\nfoo$\n$\nfoo$\n$\n \\t $\n$\nprompt$ printf \'\\n \\t \\n\\nfoo\\n\\nfoo\\n\\n \\t \\n\\n\' | sed -e :a -e \'/[^[:blank:]]/,$!d; /^[[:space:]]*$/{ $d; N; ba\' -e \'}\'\nfoo\n\nfoo\nprompt$\n
Run Code Online (Sandbox Code Playgroud)\n


mug*_*896 5

-z这可以通过 sed选项轻松解决

sed -rz 's/^\n+//; s/\n+$/\n/g' file
Hello

Welcome to
Unix and Linux
Run Code Online (Sandbox Code Playgroud)