awkでprintfを使用してコマンド出力を区切る列を指定する方法

awkでprintfを使用してコマンド出力を区切る列を指定する方法

次のように、出力からメーカー名、ファームウェアバージョン、およびカードのステータスを抽出したいと思いますfcinfo hba-port

root-#> fcinfo HBA ポート
HBAポートWWN:10000000c96a53c5
        オペレーティングシステムデバイス名:/dev/cfg/c2
        メーカー: Emulex
        モデル: LPe11000-M4
        ファームウェアバージョン:2.82a4(Z3D2.82A4)
        FCode/BIOS バージョン: ブート: 5.02a1 Fcode: 1.50a9
        所蔵番号:VM73059524
        ドライバー名: emlxs
        ドライババージョン:2.60k(2011.03.24.16.45)
        タイプ: Nポート
        ステータス:オンライン
        サポート速度: 1Gb 2Gb 4Gb
        現在の速度:4GB
        ノードWWN:20000000c96a53c5

次の方法を使用してこれら3つのフィールドを抽出しますawk

root-#> fcinfo hba-port | awk '/Manufacturer:/{m=$2}/Firmware Version:/{F=$3}/State/{print m, F, $2}'
Emulex 2.82a4 online
Emulex 2.82a4 online
Emulex 2.82a4 offline
Emulex 2.82a4 offline
Emulex 2.82a4 online
Emulex 2.82a4 online

たとえば、次のように、よりユーザーフレンドリーな形式で出力を表示したいと思います。

HBA_Manufacturer    Firmware_Version   State
--------------------------------------------
Emulex               2.82a4           online
Emulex               2.82a4           offline
Emulex               2.82a4           offline

...タイトルを追加してデータに合わせて並べ替えます。どうすればいいですか?

Solarisソリューションが必要です。 (Linuxに適用される多くのコマンドはSolarisには適用されません。)

答え1

次のコマンドを使用せずに、列をcolumn内部で完全に整列させることができます。awk

# fcinfo hba-port | awk '
                        BEGIN{man[-1]="HBA_Manufacturer"
                              ver[-1]="Firmware_Version"
                              sta[-1]="State"
                              man[0]="----------------"
                              ver[0]="----------------"
                              sta[0]="-----"
                              i=1
                             }
                        /Manufacturer:/     {man[i]=$2}
                        /Firmware Version:/ {ver[i]=$3}
                        /State:/            {sta[i]=$2; i++}
                        END {
                             maxlen1 = maxlen2 = maxlen3 = 0
                             for (j=-1; j<i; j++) {
                                 if (length(man[j]) > maxlen1) maxlen1 = length(man[j])
                                 if (length(ver[j]) > maxlen2) maxlen2 = length(ver[j])
                                 if (length(sta[j]) > maxlen3) maxlen3 = length(sta[j])
                             }
                             for (j=-1; j<i; j++) {
                                 printf("%-*s  %-*s  %-*s\n", maxlen1, man[j],
                                                              maxlen2, ver[j],
                                                              maxlen3, sta[j])
                             }
                            }'

これは入力テキスト全体を読み取り、データ(タイトルを含む)をmanverおよびsta(製造元、バージョン、および状態)配列に保存します。列ヘッダーは項目に配置され、ダッシュ[-1](ヘッダーとデータの間に行を形成する)は項目[0]に配置されます。これは出力の最初の2行になります(下記参照)。実際のデータはで始まります[1]

データの終わりに達すると、各列(ヘッダーを含む)のデータ最大長を決定し、計算された列幅を使用して配列内のすべてのデータを印刷します。

  • printf("%16s", "Emulex")印刷します          Emulex (前に10個のスペース、その後に6文字の名前、合計16文字)。
  • printf("%-16s", "Emulex")(知っている-)が印刷されますEmulex           (6桁の名前と10文字の末尾のスペース、合計16文字)。
  • printf("%-*s", 16, "Emulex")フォーマット文字列の代わりにパラメータprintf("%-16s", "Emulex")リストから取得する以外は同じことを行います。16
  • したがって、上記は次のような出力を生成します。

    HBA_Manufacturer  Firmware_Version  State
    ----------------  ----------------  -----
    Emulex            2.82a4            online
    Emulex            2.82a4            online
    Emulex            2.82a4            offline
    Emulex            2.82a4            offline
    Emulex            2.82a4            online
    Emulex            2.82a4            online
    

    列の間にさらにスペースが必要な場合は、フォーマットprintfにスペースを追加してください。たとえば"%-*s %-*s %-*s\n" 、表示された出力例に近いものを提供します。

  • 表示される出力例には、タイトルの後に連続したダッシュラインがあります。上記のように、私のコマンドは各タイトルの下に小さなダッシュラインのみを提供します。一部のデータが長い場合、これはより明白になります。

    HBA_Manufacturer         Firmware_Version  State
    ----------------         ----------------  -----
    Emulex                   2.82a4            online
    Emulex                   2.82a4            online
    Some_other_manufacturer  2.82a4            offline
    Emulex                   2.82a4            offline
    Emulex                   2.82a4            online
    Emulex                   2.82a4            online
    

    必要に応じてこの問題を解決できます。

  • 入力データが大きいと、awkすべてのデータを保存するスペースが不足する可能性があるため、この操作が失敗する可能性があります。
  • 以前のバージョンawk(Solarisなど)を使用すると、構文エラーが原因で失敗する可能性があります。これが発生した場合は、printf次のようにすべてのステートメントを1行に入力してください。
          printf("%-*s %-*s %-*s\n", maxlen1, man[j], maxlen2, ver[j], maxlen3, sta[j])

答え2

各列の希望の幅があらかじめ決められている場合awk持つprintfたとえば、20文字、15文字、10文字(間に2つのスペースを含む)の列が必要な場合は、Cと非常によく似ています。

(as in Q)  /State/{printf "%-20s  %-15s  %-10s\n", m, F, $2}

-左揃えを提供します。デフォルトは右です。通常は数値には機能しますが、テキストには機能しません。)

幅をデータに合わせて調整するには、データを配列に保存し、必要な幅を計算し、アスタリスクでこれらの幅を使用できますprintf "%-*s ", len, dataG-Manがこのcolumnショーに返信しました。これを行う方が簡単です。

答え3

次の手順で列を並べ替えることができます。

# fcinfo hba-port | awk '
                        BEGIN {printf("HBA_Manufacturer Firmware_Version State\n")
                               printf("---------------- ---------------- -----\n")
                              }
                        /Manufacturer:/ {m=$2}
                        /Firmware Version:/ {F=$3}
                        /State/ {print m, F, $2}' | column -t

これにより、次のような出力が生成されます。

HBA_Manufacturer  Firmware_Version  State
----------------  ----------------  -----
Emulex            2.82a4            online
Emulex            2.82a4            online
Emulex            2.82a4            offline
Emulex            2.82a4            offline
Emulex            2.82a4            online
Emulex            2.82a4            online

メモ:

  • 列間にさらにスペースが必要な場合は、最後に(または)オプションを使用して列間に入れる文字列を指定します。デフォルトは2つのスペースです。たとえば、4つのスペースを使用すると、表示された出力例に近い結果が得られます。--output-separator string-o string… | column -t -o " "
  • 表示される出力例には、タイトルの後に連続したダッシュラインがあります。上記のように、私のコマンドは各タイトルの下に小さなダッシュラインのみを提供します。一部のデータが長い場合、これはより明白になります。

    HBA_Manufacturer         Firmware_Version  State
    ----------------         ----------------  -----
    Emulex                   2.82a4            online
    Emulex                   2.82a4            online
    Some_other_manufacturer  2.82a4            offline
    Emulex                   2.82a4            offline
    Emulex                   2.82a4            online
    Emulex                   2.82a4            online
    

    必要に応じてこの問題を解決できます。

答え4

試行錯誤を経てタブを調整する必要があるかもしれませんが、一般的に -

awk 'BEGIN{printf("HBA_Manufacturer\t\t\tFirmware_Version\t\t\tState\n----------------------------------------\n")} {... printf("%s\t\t\t%s\t\t\t%s\n", m, f,$2) }

関連情報