这是一个示例文本。(它的名称是20210622_090009)
nvmeSerial Endpoint nvmeSpeed nvmeWidth
================================================================================
nvme0n1 c7:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme1n1 c8:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme2n1 c9:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme3n1 ca:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme4n1 85:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme5n1 86:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme6n1 87:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme7n1 88:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme8n1 41:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme9n1 42:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme10n1 43:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme11n1 44:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme12n1 45:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme13n1 46:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme14n1 47:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme15n1 48:00.0 Width x2 (downgraded)
nvme16n1 01:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme17n1 02:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme18n1 03:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme19n1 04:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme20n1 05:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme21n1 06:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme22n1 07:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme23n1 08:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme24n1 09:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme25n1 0a:00.0 Speed 32GT/s (ok) Width x2 (downgraded)
这是脚本:
#! /bin/bash
IFS_old="$IFS"
IFS=$'\n'
for line in $(cat 20210622_090009.txt | tail -n 26 | cut -f 5 | awk '{print $2}' )
do
echo "$line"
done
IFS="$IFS_old"
exit 0
脚本输出是
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
32GT/s
我想获取 nvmeSpeed(Ex:8GT/s) 无论速度是否有数字。
如您所见,nvmeSpeed innvme15n1
是一个空格。
并且输出不显示。
我的问题是:
如何将 awk 空格变成 for 循环输入?
答案1
awk
独自一人就可以做到这一切。你不需要 shell 脚本包装器,你当然不需要任何像巴洛克式的东西cat 20210622_090009.txt | tail -n 26 | cut -f 5 | awk '{print $2}'
) 这样巴洛克式的东西,并且您应该避免在任何地方使用 shell while-read 循环(或对 awk 或 perl 等语言的输出进行 for 循环)可能(参见为什么使用 shell 循环处理文本被认为是不好的做法?原因)。
经验法则:如果您发现自己在想“我想迭代 awk 的输出”,您应该将您的想法改为“我几乎肯定应该只使用 awk 来完成此操作”,或者为 awk 设置输入和输出重定向的 shell 包装器进行批量加工工作。 Perl 和大多数其他语言也是如此。任何其他语言都会比 shell 更好地完成处理工作,并且尝试使用 shell 只会让您的工作变得更加困难。
无论如何,如果正好有 8 列 ( NF == 8
),则以下脚本将打印第 4 列。如果少于 8 列 ( NF < 8
),则打印空行。在这两种情况下,它都会忽略每个输入文件开头的两个标题行(它可以处理一个或多个文件名参数。 FNR < 3 {next}
在 awk 中,NR 是读取的总行数,而 FNR 是读取的行数)当前的文件)。
$ awk 'FNR < 3 {next}; NF == 8 {print $4}; NF < 8 {print ""}' 20210622_090009.txt
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
32GT/s
答案2
看起来您有固定宽度的字段,因此,使用 GNU awk 作为 FIELDWIDTHS 和 gensub():
$ awk -v FIELDWIDTHS='16 12 24 *' '
NR>2 {
gsub(/^ *| *$/,"",$3)
print gensub(/.* ([^ ]+) .*/,"\\1",1,$3)
}
' file
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
8GT/s
32GT/s
上面首先通过每个字段的宽度来标识每个字段的内容:
$ cat file
nvmeSerial Endpoint nvmeSpeed nvmeWidth
================================================================================
nvme0n1 c7:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme1n1 c8:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
nvme15n1 48:00.0 Width x2 (downgraded)
nvme25n1 0a:00.0 Speed 32GT/s (ok) Width x2 (downgraded)
$ cat tst.awk
BEGIN { FIELDWIDTHS="16 12 24 *" }
NR != 2 {
print
for (i=1; i<=NF; i++) {
gsub(/^ *| *$/,"",$i)
print "\t" i, "<" $i ">"
}
print "-----"
}
$ awk -f tst.awk file
nvmeSerial Endpoint nvmeSpeed nvmeWidth
1 <nvmeSerial>
2 <Endpoint>
3 <nvmeSpeed>
4 <nvmeWidth>
-----
nvme0n1 c7:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
1 <nvme0n1>
2 <c7:00.0>
3 <Speed 8GT/s (ok)>
4 <Width x2 (downgraded)>
-----
nvme1n1 c8:00.0 Speed 8GT/s (ok) Width x2 (downgraded)
1 <nvme1n1>
2 <c8:00.0>
3 <Speed 8GT/s (ok)>
4 <Width x2 (downgraded)>
-----
nvme15n1 48:00.0 Width x2 (downgraded)
1 <nvme15n1>
2 <48:00.0>
3 <>
4 <Width x2 (downgraded)>
-----
nvme25n1 0a:00.0 Speed 32GT/s (ok) Width x2 (downgraded)
1 <nvme25n1>
2 <0a:00.0>
3 <Speed 32GT/s (ok)>
4 <Width x2 (downgraded)>
-----
然后选择要打印的第三个字段的部分就很简单了。例如gensub()
像我一样使用。无论任何行中缺少哪些字段、任何字段中有多少个单词等,上述内容都将起作用。
答案3
另一种方法假设固定宽度字段(仅提取其中一个字段,并假设它始终以 6 个字符“Speed”开头(如果它不为空):
cut -c35-52 file | sed '1,2d;s/ .*//'
或者匹配“Speed”:
awk -F ' Speed +' 'NR>2 {sub(/ .*/,"",$2); print $2}' file
sed -E '1,2d;s/.* Speed +([^ ]+).*/\1/;t;c\\' file
perl -nE 'say m{\sSpeed\s+(\S+)} if $.>2' file
答案4
awk 'NR>2{if($4 ~ /^[0-9].*GT/){print $1" =======>" $4}else{if($4 !~ /^[0-9].*GT/){print $1"==================== doesnt contain speed==========================="}}}' filename
输出
nvme0n1 =======>8GT/s
nvme1n1 =======>8GT/s
nvme2n1 =======>8GT/s
nvme3n1 =======>8GT/s
nvme4n1 =======>8GT/s
nvme5n1 =======>8GT/s
nvme6n1 =======>8GT/s
nvme7n1 =======>8GT/s
nvme8n1 =======>8GT/s
nvme9n1 =======>8GT/s
nvme10n1 =======>8GT/s
nvme11n1 =======>8GT/s
nvme12n1 =======>8GT/s
nvme13n1 =======>8GT/s
nvme14n1 =======>8GT/s
nvme15n1==================== doesnt contain speed===========================
nvme16n1 =======>8GT/s
nvme17n1 =======>8GT/s
nvme18n1 =======>8GT/s
nvme19n1 =======>8GT/s
nvme20n1 =======>8GT/s
nvme21n1 =======>8GT/s
nvme22n1 =======>8GT/s
nvme23n1 =======>8GT/s
nvme24n1 =======>8GT/s
nvme25n1 =======>32GT/s