
Hier ist ein Beispieltext. (Der Name lautet 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)
Hier ist das Skript:
#! /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
Die Skriptausgabe ist
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
Ich möchte die NVME-Geschwindigkeit (z. B. 8 GT/s) erfassen, unabhängig davon, ob die Geschwindigkeit eine Zahl enthält oder nicht.
Wie Sie sehen, nvme15n1
ist „nvmeSpeed“ ein Leerzeichen.
Und die Ausgabe wird nicht angezeigt.
Meine Frage ist:
Wie kann man aus einem Leerzeichen eine For-Schleifen-Eingabe machen?
Antwort1
awk
allein kann all dies tun. Sie brauchen keinen Shell-Skript-Wrapper, Sie brauchen sicherlich nichts so Barockes wie cat 20210622_090009.txt | tail -n 26 | cut -f 5 | awk '{print $2}'
), und Sie sollten die Verwendung einer Shell-while-read-Schleife (oder einer for-Schleife über die Ausgabe einer Sprache wie awk oder perl) nach Möglichkeit vermeiden (sieheWarum gilt die Verwendung einer Shell-Schleife zur Textverarbeitung als schlechte Praxis?für die Gründe, warum).
Faustregel: Wenn Sie sich jemals dabei ertappen, zu denken „Ich möchte die Ausgabe von awk durchlaufen“, sollten Sie Ihre Denkweise ändern und sagen „Ich sollte das mit ziemlicher Sicherheit nur mit awk machen“ oder mit einem Shell-Wrapper, der die Eingabe- und Ausgabeumleitung für awk einrichtet, um die Massenverarbeitungsarbeit zu erledigen. Dasselbe gilt für Perl und die meisten anderen Sprachen. Jede andere Sprache erledigt die Verarbeitungsarbeit besser als Shell, und Sie werden sich die Arbeit nur erschweren, wenn Sie versuchen, sie mit Shell zu erledigen.
Das folgende Skript druckt jedenfalls Spalte 4, wenn genau 8 Spalten vorhanden sind ( NF == 8
). Wenn weniger als 8 Spalten vorhanden sind ( NF < 8
), wird eine leere Zeile gedruckt. In beiden Fällen ignoriert es die beiden Kopfzeilen am Anfang jeder Eingabedatei (es kann ein oder mehrere Dateinamenargumente verarbeiten. FNR < 3 {next}
. In awk ist NR die Gesamtzahl der gelesenen Zeilen, während FNR die Zeilennummer deraktuellDatei).
$ 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
Antwort2
Sieht aus, als hätten Sie Felder mit fester Breite. Verwenden Sie daher GNU awk für FIELDWIDTHS und 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
Oben wird zunächst der Inhalt jedes Felds anhand der Breite jedes Felds identifiziert:
$ 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)>
-----
und dann ist es ganz einfach, den Teil des 3. Felds auszuwählen, den Sie drucken möchten. Verwenden Sie beispielsweise gensub()
wie ich. Das Obige funktioniert unabhängig davon, welche Felder in einer Zeile fehlen, wie viele Wörter in einem Feld sind usw.
Antwort3
Eine andere Methode, die von Feldern fester Breite ausgeht (extrahiert nur eines der Felder und nimmt an, dass es immer mit den 6 Zeichen „Speed“ beginnt, wenn es nicht leer ist):
cut -c35-52 file | sed '1,2d;s/ .*//'
Oder Match " Geschwindigkeit ":
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
Antwort4
awk 'NR>2{if($4 ~ /^[0-9].*GT/){print $1" =======>" $4}else{if($4 !~ /^[0-9].*GT/){print $1"==================== doesnt contain speed==========================="}}}' filename
Ausgabe
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