
サンプルテキストはこちらです。(名前は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(例:8GT/s) を取得したいです。
ご覧のとおり、nvmeSpeed はnvme15n1
空白です。
そして出力は表示されません。
私の質問は次のとおりです:
空白を awk で for ループ入力にするにはどうすればよいでしょうか?
答え1
awk
だけでこれらすべてを行うことができます。シェルスクリプトラッパーは必要ありません。 ) のような複雑なものももちろん必要ありませんcat 20210622_090009.txt | tail -n 26 | cut -f 5 | awk '{print $2}'
。また、可能な限り、シェルの while-read ループ (または awk や perl などの言語の出力に対する for ループ) の使用は避けてください (シェル ループを使用してテキストを処理するのはなぜ悪い習慣だと考えられるのでしょうか?理由については。
経験則: 「awk の出力を反復処理したい」と考えている場合は、「おそらく awk だけでこれを行う」か、awk が一括処理作業を行うために入力と出力のリダイレクトを設定するシェル ラッパーを使用するように考えを変える必要があります。Perl や他のほとんどの言語でも同様です。他の言語はシェルよりも処理作業が優れているため、シェルで処理しようとすると作業が困難になるだけです。
いずれにしても、次のスクリプトは、ちょうど 8 列 ( ) の場合、列 4 を出力しますNF == 8
。列が 8 列未満 ( NF < 8
) の場合、空白行を出力します。どちらの場合も、各入力ファイルの先頭にある 2 つのヘッダー行は無視されます (1 つ以上のファイル名引数を処理できます)。awk FNR < 3 {next}
では、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
固定幅のフィールドがあるようなので、FIELDWIDTHS と gensub() に GNU awk を使用します。
$ 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)>
-----
そして、印刷したい 3 番目のフィールドの部分を選択するのは簡単です。たとえば、gensub()
私が行ったように使用します。上記は、どの行にどのフィールドが欠落しているか、どのフィールドにいくつの単語が含まれているかなどに関係なく機能します。
答え3
固定幅フィールドを前提とする別の方法 (フィールドの 1 つだけを抽出し、空でない場合は常に 6 文字の「Speed」で始まると想定します):
cut -c35-52 file | sed '1,2d;s/ .*//'
または「スピード」に一致します:
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