打印文件中的第一个和最后一个非空(或仅非空格)行

打印文件中的第一个和最后一个非空(或仅非空格)行

我想打印文件中的第一个和最后一个非空或非空白行,最好使用sedor awk

  • 输入文件:
    123 345
    456 087
    er 56
    32 78
    
    
    注意后面有一个空行32 78
  • 期望的输出:
    123 345
    32 78
    

答案1

请注意,我在这里回答两个问题,因为问题中的文本已修改:

  1. 我们如何从文件中输出第一行和倒数第二行(最初的问题包含“倒数第二行”一词)?

  2. 我们如何输出第一行和最后一个非空、非空行?


使用ed编辑器,它的行寻址比 稍微灵活一些sed,主要是因为将所有数据读入内存而不是一次读一行:

$ printf '%s\n' 1p '$-1p' Q | ed -s file
123 345
32 78

这将在退出之前打印输入文件中的第一行和倒数第二行。倒数第二行使用 来寻址$-1,可以缩短为$-.

如果我们不知道末尾是否有一个空行,我们可以从第 1 行向后搜索包含某些内容的行并打印:

$ printf '%s\n' 1p '?[[:graph:]]?p' Q | ed -s file
123 345
32 78

使用sed

$ sed -n -e 1p -e '${ g; p; }' -e h file
123 345
32 78

这首先关闭每行的默认输出-n。然后它打印第一行。所有行都使用 保存到保留空间h,并且在最后一行,我们使用 获取保留空间g并打印它。由于最后两个表达式的顺序,这将打印倒数第二行。

通过一个小的修改,我们可以更改它以输出最后一个非空行,无论它是否是倒数第二行:

$ sed -n -e 1p -e '/[[:graph:]]/h' -e '${ g; p; }' file
123 345
32 78

grep通过和的组合sed,我们可以首先过滤掉所有空行或看起来空行,然后只输出第一行和最后一行:

$ grep '[[:graph:]]' file | sed -n -e 1p -e '$p'
123 345
32 78

请注意,这也将输出第一个非空行,即使这不是原始数据中的第一行。

答案2

以下 awk程序将执行此操作:

awk 'NF{last=$0; if (!c++) print;} END {if (c>1) print last}' file.txt
  • awk默认情况下,将输入行拆分为“空白”字段,即连续的空格和制表符。字段的数量存储在 中NF。如果一行完全为空,或仅由空格组成,NF则为零。
  • 如果程序遇到真正且视觉上的非空行,即NF非零且计算结果为true,则它将该行内容存储在缓冲区 中last。如果这是第一行(计数器变量c将被取消设置并计算为false),它将打印当前行。无论如何,它都会增加,c因此对于第一个非空行,这种情况只能发生一次。
  • 最后,如果打印last最后一个非空行的内容,但前提是c>1,这样如果只有一行非空,则该行将只打印一次。如果所有行均为空,c则计算结果为 0,并且即使在子句中也不会打印任何内容END

答案3

sed -n '/^$/d; p; :a; n; /^$/!h; $!ba; g; /^$/!p' file.txt

测试文件内容:

==> file_1.txt <==
123 345
456 087

er 56

32 78

==> file_2.txt <==    

123 345
456 087

er 56

32 78    

==> file_3.txt <==
123 345
456 087

er 56

32 78
==> file_4.txt <==


123 345
456 087

er 56

32 78  


==> file_5.txt <==
123 345

测试

for f in file_{1..5}.txt; do
    echo "==> $f <=="
    sed -n '/^$/d; p; :a; n; /^$/!h; $!ba; g; /^$/!p' "$f"
done

输出:

==> file_1.txt <==
123 345
32 78
==> file_2.txt <==
123 345
32 78
==> file_3.txt <==
123 345
32 78
==> file_4.txt <==
123 345
32 78
==> file_5.txt <==
123 345

相关内容