我想打印文件中的第一个和最后一个非空或非空白行,最好使用sed
or awk
。
- 输入文件:
注意后面有一个空行123 345 456 087 er 56 32 78
32 78
。 - 期望的输出:
123 345 32 78
答案1
请注意,我在这里回答两个问题,因为问题中的文本已修改:
我们如何从文件中输出第一行和倒数第二行(最初的问题包含“倒数第二行”一词)?
我们如何输出第一行和最后一个非空、非空行?
使用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