我经常想要 grep 包含一些标题行的进程的输出。但如果 grep 会删除所有实际内容行,我不想显示标题行。为此,我需要一个类似于的命令tail
,但它不是只返回 n 行,而是返回全部行,但前提是至少有 n 行(标题)。
一位同事编写了一个小型 Python 工具来执行此操作,但需要在我需要执行此操作的所有计算机上安装它。
是否有一个简短的命令行可以使用标准工具(也许是 awk?)实现这种效果?
答案1
您可以将第一n
行保存在 awk 数组中,并在(如果)看到 line 时将它们写出来n + 1
,即当您发现至少有一个数据行时。
Awk_N='
FNR <= N { X[FNR] = $0; next; }
FNR == N + 1 {
for (j = 1; j in X; ++j) print X[j];
delete X;
}
{ print; }
'
awk -v N=7 "${Awk_N}"
我创建了7
一个 shell 空间变量,这样就可以在不编辑 Awk 部分的情况下替换它。
Awk 部分被预先声明为单引号多行 shell 字符串变量,以整理您的管道。
awk
您可能还会考虑是否可以同时将 grep 逻辑折叠到 中。
稍微简短的版本,存储所有行。
awk '{ X[NR] = $0 } END { if (NR > 3) for (j = 1; j in X; ++j) print X[j] }'
这可以最大限度地减少字符数(以牺牲可读性为代价)。
awk '{X[NR]=$0}END{if(NR>3)for(j=1;j in X;++j)print X[j]}'
答案2
这是sed
一行(假设您想打印所有内容,如果至少有 4 行,即n=4
):
cmd | sed -e '4,$!{H;1h;d;}' -e '4H;4x'
所以,如果你想使用变量
cmd | sed -e "${n}"',$!{H;1h;d;}' -e "${n}H;${n}x"
这样做的作用是将第一n-1
行保存在H
旧缓冲区中并d
从模式空间中删除它们,因此不会打印任何内容...除非sed
接收到至少一行 - 第一n
行,并将其添加到H
旧空间中,然后x
更改缓冲区所以现在模式空间包含1
到 的行n
。剩下的就是自动打印的问题了。
在某些非 GNU 设置上,您可能需要这样编写(假设n=21
这次):
cmd | sed '21,$!{
H;1h;d
}
21H;21x'
答案3
如果标头有 7 行长,如果输入长度 <= 7,我们可以将其删除。使用 Perl 或 (gnu)sed:
cmd... | perl -0pe 's/^(.*\n){,7}$//'
cmd... | sed -zE 's/^(.*\n){,7}$//m'
(避免使用千兆字节输入执行此操作)
答案4
我设法使用tee
and解决了这个问题wc
:
cmd | tee x | [ `wc -l <&0` -gt 3 ] && cat x && rm x
在本例中,如果超过 3 行,则输出整个输出。
NB1 当您只需要知道是否超过 3 行时,计算整个文件的行数就显得有些过分了。
NB2 进一步降低性能,这会写入一个临时文件。据我了解,使用mkfifo
会使它进入内存,但命令会更长。