如何使用 AWK 删除输出的最后两行?
How to delete last two lines of an output using AWK?
我正在尝试制作一个输出的图形表示,显示当天服务器的可用内存(大约按小时显示),从该输出我不想要前两行和后两行,前两行我可以用 NR 轻松删除,虽然我在最后两行遇到了麻烦,但我发现的唯一方法是反转整个输出删除前两行,然后再次反转到正常状态。
有任何 better/correct 方法可以删除最后两行但在 AWK 中执行吗?
这是我目前所拥有的并且工作正常。
echo 'graphics (freemem)'
echo 'GiB 0 500k 1M 1,5M'
sar -r | tail -r | awk 'NR > 2{ print }' | tail -r | nawk '
NR > 4{
LINE = sprintf("%" int(( / 100000)*2 )"s", " ");
gsub(/ /, "#", LINE);
print , LINE; }
'
更新
所以我用另一种方式做了,因为它更容易阅读脚本并且它对我有用,但对于任何其他需要这样做的人来说,要么使用我以前的方式,要么使用下面的人已经回答了。
echo 'graphics (freemem)'
echo 'GiB 0 500k 1M 1,5M'
sar -r | nawk '
NR > 4 && !~ /Average/ && !~ /^$/ {
LINE = sprintf("%" int(( * 2) / 100000 )"s", " ");
gsub(/ /, "#", LINE);
print , LINE; }
'
更新 2
所以我想做的是监控数据的图形表示,这个输出大约每小时更新一次,请记住,在一天中的不同时间,行的长度会有所不同。所以这是我得到的 sar -r
的实际输出。
.
SunOS doc 5.10
00:00:00 freemem freeswap
01:00:01 1624430 19474799
02:00:00 1624421 19474738
03:00:00 1624413 19474683
04:00:00 1624527 19475309
05:00:00 1624525 19475290
06:00:00 1624517 19475232
07:00:01 1624510 19475176
08:00:00 1624503 19475120
08:20:00 1539793 18771472
08:40:00 1509924 18535201
09:00:00 1500681 18492050
09:20:00 1494254 18435535
09:40:00 1479623 18266664
10:00:00 1486372 18317241
10:20:00 1480565 18269032
10:40:00 1479030 18260247
11:00:01 1476462 18237731
11:20:00 1475999 18234221
11:40:00 1478854 18259827
12:00:00 1478223 18254861
12:20:00 1482956 18294572
12:40:00 1479061 18260565
13:00:00 1470463 18185441
13:20:00 1474090 18217961
13:40:00 1478585 18257393
14:00:00 1478219 18255445
14:20:00 1474327 18223749
14:40:00 1470468 18190676
15:00:00 1471941 18204282
15:20:00 1474138 18223380
15:40:00 1471698 18202561
16:00:00 1470316 18191099
16:20:00 1467203 18163653
16:40:00 1468943 18179148
Average 1549994 18855701
所以我们不关心 freeswap,我们不使用它。我们只关心 freemem 的结果。所以我想做的是通过计算将该列和 "translate" 数字作为“#”的条目,这样我以后就可以在图形表示中指定数据量。虽然,输出的开头和结尾有一些我不需要的行,所以我需要删除它们。
这是我现在的工作代码
echo '\ngraphics (freemem)'
echo 'GiB 0 500k 1M 1,5M'
sar -r | awk 'NR > 2 {print P2} {P2=P; P=[=13=]}' |
nawk '
NR > 4 {
LINE = sprintf("%" int(( * 2) / 100000 )"s", " ");
gsub(/ /, "#", LINE);
print , LINE; }
'
所以正确的输出是这个:
graphics (freemem)
GiB 0 500k 1M 1,5M
01:00:01 ################################
02:00:00 ################################
03:00:00 ################################
04:00:00 ################################
05:00:00 ################################
06:00:00 ################################
07:00:01 ################################
08:00:00 ################################
08:20:00 ##############################
08:40:00 ##############################
09:00:00 ##############################
09:20:00 #############################
09:40:00 #############################
10:00:00 #############################
10:20:00 #############################
10:40:00 #############################
11:00:01 #############################
11:20:00 #############################
11:40:00 #############################
12:00:00 #############################
12:20:00 #############################
12:40:00 #############################
13:00:00 #############################
13:20:00 #############################
13:40:00 #############################
14:00:00 #############################
14:20:00 #############################
14:40:00 #############################
15:00:00 #############################
15:20:00 #############################
15:40:00 #############################
16:00:00 #############################
16:20:00 #############################
您可以存储该行,做一些事情并在一段时间后打印,这样您就可以知道您是否在最后一行。但是当你有 head
和 tail
.
这样的工具时,打高尔夫球就太过分了
只需将输出通过管道传输到 head
,然后再将其传递到 awk
:
head -n -2
测试
$ seq 10
1
2
3
4
5
6
7
8
9
10
$ seq 10 | head -n -2
1
2
3
4
5
6
7
8
因为你没有 GNU 头允许你这样做,你可以用 awk
:
来保存变量
awk '{if (prev_prev_line) print prev_prev_line; prev_prev_line=prev_line}
{prev_line=[=12=]}'
这会换行,因此您在 prev_prev_line
中有两行之前的内容:
NR [=13=] prev_line prev_prev_line
1 1 - -
2 2 1 -
3 3 2 1
4 4 3 2
....
NR-1 NR-1 NR-2 NR-3
NR NR NR-1 NR-2
因此,由于您正在使用 prev_prev_line
,因此您将最终处理从第一行到第 (NR-2)
行。
所以在 prev_prev_line
中你有两行前出现的行。这样,您就不会在输出中使用最后两行。
通过示例查看它是如何工作的:
$ awk '{if (prev_prev_line) print NR,prev_prev_line; prev_prev_line=prev_line}
{prev_line=[=14=]}' < <(seq 10)
3 1
4 2
5 3
6 4
7 5
8 6
9 7
10 8
如果没有别的办法
... | sed '$d' | sed '$d'
逃出 awk 以对文件进行一些计算
awk '{if (NR > 2 && NR < '$(( $(wc -l <$file) -1))')print [=10=]}' $file
如果记录数大于 2,我们将跳过前 2 行。如果它小于总行数减 1,则我们在最后两行之前停止(如果使用 <=,则可以使用 -2)。
$ seq 5 | awk 'NR>2{print p2} {p2=p; p=[=10=]}'
1
2
3
鉴于您编辑的问题:
$ cat tst.awk
BEGIN {
print "\ngraphics (freemem)"
print "GiB 0 500k 1M 1,5M"
}
/^[0-9: ]+$/ {
line = sprintf("%*s", int((*2)/100000), "")
gsub(/ /,"#",line)
print , line
}
.
$ awk -f tst.awk file
graphics (freemem)
GiB 0 500k 1M 1,5M
01:00:01 ################################
02:00:00 ################################
03:00:00 ################################
04:00:00 ################################
05:00:00 ################################
06:00:00 ################################
07:00:01 ################################
08:00:00 ################################
08:20:00 ##############################
08:40:00 ##############################
09:00:00 ##############################
09:20:00 #############################
09:40:00 #############################
10:00:00 #############################
10:20:00 #############################
10:40:00 #############################
11:00:01 #############################
11:20:00 #############################
11:40:00 #############################
12:00:00 #############################
12:20:00 #############################
12:40:00 #############################
13:00:00 #############################
13:20:00 #############################
13:40:00 #############################
14:00:00 #############################
14:20:00 #############################
14:40:00 #############################
15:00:00 #############################
15:20:00 #############################
15:40:00 #############################
16:00:00 #############################
16:20:00 #############################
16:40:00 #############################
我正在尝试制作一个输出的图形表示,显示当天服务器的可用内存(大约按小时显示),从该输出我不想要前两行和后两行,前两行我可以用 NR 轻松删除,虽然我在最后两行遇到了麻烦,但我发现的唯一方法是反转整个输出删除前两行,然后再次反转到正常状态。
有任何 better/correct 方法可以删除最后两行但在 AWK 中执行吗?
这是我目前所拥有的并且工作正常。
echo 'graphics (freemem)'
echo 'GiB 0 500k 1M 1,5M'
sar -r | tail -r | awk 'NR > 2{ print }' | tail -r | nawk '
NR > 4{
LINE = sprintf("%" int(( / 100000)*2 )"s", " ");
gsub(/ /, "#", LINE);
print , LINE; }
'
更新
所以我用另一种方式做了,因为它更容易阅读脚本并且它对我有用,但对于任何其他需要这样做的人来说,要么使用我以前的方式,要么使用下面的人已经回答了。
echo 'graphics (freemem)'
echo 'GiB 0 500k 1M 1,5M'
sar -r | nawk '
NR > 4 && !~ /Average/ && !~ /^$/ {
LINE = sprintf("%" int(( * 2) / 100000 )"s", " ");
gsub(/ /, "#", LINE);
print , LINE; }
'
更新 2
所以我想做的是监控数据的图形表示,这个输出大约每小时更新一次,请记住,在一天中的不同时间,行的长度会有所不同。所以这是我得到的 sar -r
的实际输出。
.
SunOS doc 5.10
00:00:00 freemem freeswap
01:00:01 1624430 19474799
02:00:00 1624421 19474738
03:00:00 1624413 19474683
04:00:00 1624527 19475309
05:00:00 1624525 19475290
06:00:00 1624517 19475232
07:00:01 1624510 19475176
08:00:00 1624503 19475120
08:20:00 1539793 18771472
08:40:00 1509924 18535201
09:00:00 1500681 18492050
09:20:00 1494254 18435535
09:40:00 1479623 18266664
10:00:00 1486372 18317241
10:20:00 1480565 18269032
10:40:00 1479030 18260247
11:00:01 1476462 18237731
11:20:00 1475999 18234221
11:40:00 1478854 18259827
12:00:00 1478223 18254861
12:20:00 1482956 18294572
12:40:00 1479061 18260565
13:00:00 1470463 18185441
13:20:00 1474090 18217961
13:40:00 1478585 18257393
14:00:00 1478219 18255445
14:20:00 1474327 18223749
14:40:00 1470468 18190676
15:00:00 1471941 18204282
15:20:00 1474138 18223380
15:40:00 1471698 18202561
16:00:00 1470316 18191099
16:20:00 1467203 18163653
16:40:00 1468943 18179148
Average 1549994 18855701
所以我们不关心 freeswap,我们不使用它。我们只关心 freemem 的结果。所以我想做的是通过计算将该列和 "translate" 数字作为“#”的条目,这样我以后就可以在图形表示中指定数据量。虽然,输出的开头和结尾有一些我不需要的行,所以我需要删除它们。
这是我现在的工作代码
echo '\ngraphics (freemem)'
echo 'GiB 0 500k 1M 1,5M'
sar -r | awk 'NR > 2 {print P2} {P2=P; P=[=13=]}' |
nawk '
NR > 4 {
LINE = sprintf("%" int(( * 2) / 100000 )"s", " ");
gsub(/ /, "#", LINE);
print , LINE; }
'
所以正确的输出是这个:
graphics (freemem)
GiB 0 500k 1M 1,5M
01:00:01 ################################
02:00:00 ################################
03:00:00 ################################
04:00:00 ################################
05:00:00 ################################
06:00:00 ################################
07:00:01 ################################
08:00:00 ################################
08:20:00 ##############################
08:40:00 ##############################
09:00:00 ##############################
09:20:00 #############################
09:40:00 #############################
10:00:00 #############################
10:20:00 #############################
10:40:00 #############################
11:00:01 #############################
11:20:00 #############################
11:40:00 #############################
12:00:00 #############################
12:20:00 #############################
12:40:00 #############################
13:00:00 #############################
13:20:00 #############################
13:40:00 #############################
14:00:00 #############################
14:20:00 #############################
14:40:00 #############################
15:00:00 #############################
15:20:00 #############################
15:40:00 #############################
16:00:00 #############################
16:20:00 #############################
您可以存储该行,做一些事情并在一段时间后打印,这样您就可以知道您是否在最后一行。但是当你有 head
和 tail
.
只需将输出通过管道传输到 head
,然后再将其传递到 awk
:
head -n -2
测试
$ seq 10
1
2
3
4
5
6
7
8
9
10
$ seq 10 | head -n -2
1
2
3
4
5
6
7
8
因为你没有 GNU 头允许你这样做,你可以用 awk
:
awk '{if (prev_prev_line) print prev_prev_line; prev_prev_line=prev_line}
{prev_line=[=12=]}'
这会换行,因此您在 prev_prev_line
中有两行之前的内容:
NR [=13=] prev_line prev_prev_line
1 1 - -
2 2 1 -
3 3 2 1
4 4 3 2
....
NR-1 NR-1 NR-2 NR-3
NR NR NR-1 NR-2
因此,由于您正在使用 prev_prev_line
,因此您将最终处理从第一行到第 (NR-2)
行。
所以在 prev_prev_line
中你有两行前出现的行。这样,您就不会在输出中使用最后两行。
通过示例查看它是如何工作的:
$ awk '{if (prev_prev_line) print NR,prev_prev_line; prev_prev_line=prev_line}
{prev_line=[=14=]}' < <(seq 10)
3 1
4 2
5 3
6 4
7 5
8 6
9 7
10 8
如果没有别的办法
... | sed '$d' | sed '$d'
逃出 awk 以对文件进行一些计算
awk '{if (NR > 2 && NR < '$(( $(wc -l <$file) -1))')print [=10=]}' $file
如果记录数大于 2,我们将跳过前 2 行。如果它小于总行数减 1,则我们在最后两行之前停止(如果使用 <=,则可以使用 -2)。
$ seq 5 | awk 'NR>2{print p2} {p2=p; p=[=10=]}'
1
2
3
鉴于您编辑的问题:
$ cat tst.awk
BEGIN {
print "\ngraphics (freemem)"
print "GiB 0 500k 1M 1,5M"
}
/^[0-9: ]+$/ {
line = sprintf("%*s", int((*2)/100000), "")
gsub(/ /,"#",line)
print , line
}
.
$ awk -f tst.awk file
graphics (freemem)
GiB 0 500k 1M 1,5M
01:00:01 ################################
02:00:00 ################################
03:00:00 ################################
04:00:00 ################################
05:00:00 ################################
06:00:00 ################################
07:00:01 ################################
08:00:00 ################################
08:20:00 ##############################
08:40:00 ##############################
09:00:00 ##############################
09:20:00 #############################
09:40:00 #############################
10:00:00 #############################
10:20:00 #############################
10:40:00 #############################
11:00:01 #############################
11:20:00 #############################
11:40:00 #############################
12:00:00 #############################
12:20:00 #############################
12:40:00 #############################
13:00:00 #############################
13:20:00 #############################
13:40:00 #############################
14:00:00 #############################
14:20:00 #############################
14:40:00 #############################
15:00:00 #############################
15:20:00 #############################
15:40:00 #############################
16:00:00 #############################
16:20:00 #############################
16:40:00 #############################