Wie kann man ein Leerzeichen in eine For-Schleifen-Eingabe umwandeln?

Wie kann man ein Leerzeichen in eine For-Schleifen-Eingabe umwandeln?

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, nvme15n1ist „nvmeSpeed“ ein Leerzeichen.

Und die Ausgabe wird nicht angezeigt.

Meine Frage ist:

Wie kann man aus einem Leerzeichen eine For-Schleifen-Eingabe machen?

Antwort1

awkallein 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

verwandte Informationen