GNU/Linux >> Linux の 問題 >  >> Linux

AWKコマンド入門[初心者向けガイド]

AWKコマンドは、Unixの初期の時代にまでさかのぼります。これはPOSIX標準の一部であり、Unixライクなシステムで利用できるはずです。そしてそれを超えて。

Perlのような多目的言語と比較して、その古さや機能の欠如のために時々信用を失いますが、AWKは私が日常業務で使用するのが好きなツールのままです。比較的複雑なプログラムを作成する場合もありますが、強力なワンライナーのおかげで、データファイルの問題を解決するために作成することもできます。

したがって、これがまさにこの記事の目的です。便利なタスクを実行するために80文字未満でAWKパワーを活用する方法を示します。この記事は完全なAWKチュートリアルを目的としたものではありませんが、最初にいくつかの基本的なコマンドを含めたので、これまでの経験がほとんどないかまったくない場合でも、AWKのコアコンセプトを理解できます。

このAWKチュートリアルのサンプルファイル

その記事で説明されているすべてのワンライナーは、同じデータファイルでテストされます:

cat file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

そのファイルのコピーは、GitHubでオンラインで入手できます。

AWKの事前定義された自動変数を知る

AWKは、いくつかの事前定義された自動変数をサポートしています。 あなたがあなたのプログラムを書くのを助けるために。それらの中であなたはしばしば遭遇するでしょう:

RS レコード区切り文字。 AWKは、一度に1レコードずつデータを処理します。レコードセパレータは、入力データストリームをレコードに分割するために使用される区切り文字です。デフォルトでは、これは改行文字です。したがって、変更しない場合、レコードは入力ファイルの1行になります。

NR 現在の入力レコード番号。 レコードに標準の改行区切り文字を使用している場合、これは現在の入力行番号と一致します。

FS / OFS フィールド区切り文字として使用される文字。 AWKはレコードを読み取ると、FSの値に基づいてレコードをさまざまなフィールドに分割します。 。 AWKが出力にレコードを出力すると、フィールドに再結合しますが、今回はOFSを使用します FSの代わりにセパレータ セパレータ。通常、FS およびOFS 同じですが、これは必須ではありません。 「空白」は両方のデフォルト値です。

NF –現在のレコードのフィールド数。フィールドに標準の「空白」区切り文字を使用している場合、これは現在のレコードの単語数と一致します。

他にも多かれ少なかれ標準的なAWK変数が利用できるので、詳細については特定のAWK実装マニュアルを確認する価値があります。ただし、このサブセットは、興味深いワンライナーを書き始めるのにすでに十分です。

A。 AWKコマンドの基本的な使用法

1。すべての行を印刷する

この例はほとんど役に立たないが、それでもAWK構文の良い紹介になるだろう:

awk '1 { print }' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

AWKプログラムは、1つまたは複数のpattern { action }で構成されています ステートメント。

場合、特定のレコード (「行」)入力ファイルのパターン ゼロ以外の値(AWKでは「true」に相当)に評価され、対応するアクションブロックのコマンド 実行されます。上記の例では、1 はゼロ以外の定数、{ print } アクションブロックは、入力レコードごとに実行されます。

もう1つのトリックは、{ print }です。 明示的に指定しない場合にAWKによって使用されるデフォルトのアクションブロックです。したがって、上記のコマンドは次のように短縮できます。

awk 1 file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

ほとんど役に立たないので、次のAWKプログラムはその入力を消費しますが、出力には何も生成しません:

awk 0 file

2。ファイルヘッダーを削除する

awk 'NR>1' file
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

これは明示的に書くことと同じです:

awk 'NR>1 { print }' file
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

このワンライナーは、最初のファイルを除いて入力ファイルのレコードを書き込みます。その場合、条件は1>1であるためです。 これは明らかに真実ではありません。

このプログラムはRSのデフォルト値を使用しているため 、実際には、入力ファイルの最初の行を破棄します。

3。範囲内の行を印刷する

これは前の例の単なる一般化であり、&&と言うことを除いて、多くの説明に値するものではありません。 は論理的なandです 演算子:

awk 'NR>1 && NR < 4' file
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team

4。空白のみの行を削除する

awk 'NF' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support
17,05 apr 2019,abhishek,guest

AWKは、FSで指定されたフィールド区切り文字に基づいて、各レコードをフィールドに分割します 変数。デフォルトのフィールド区切り文字は1つまたは複数の空白文字です。 (別名、スペースまたはタブ)。これらの設定では、少なくとも1つの非空白文字を含むレコードには、少なくとも1つのフィールドが含まれます。

つまり、NFが発生する唯一のケースです。 is 0(“ false”)は、レコードにスペースのみが含まれている場合です。したがって、そのワンライナーは、少なくとも1つの非スペース文字を含むレコードのみを印刷します。

5。すべての空白行を削除する

awk '1' RS='' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support

17,05 apr 2019,abhishek,guest

このワンライナーは、RSかどうかを指定するあいまいなPOSIXルールに基づいています は空の文字列に設定されます。「その後、レコードはと1つ以上の空白行で構成されるシーケンスで区切られます。」

POSIXの用語で言及する価値があるのは、空白行は完全に空の行です。空白のみを含む行は「空白」としてカウントされません。

6。フィールドの抽出

これはおそらくAWKの最も一般的なユースケースの1つであり、データファイルのいくつかの列を抽出します。

awk '{ print $1, $3}' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
        ,
,
,
17,abhishek

ここでは、入力フィールドと出力フィールドの両方のセパレータを明示的にコマに設定します。 AWKがレコードをフィールドに分割すると、最初のフィールドの内容が$ 1に格納され、2番目のフィールドの内容が$2に格納されます。ここでは使用しませんが、$0がレコード全体です。

このワンライナーでは、パターンのないアクションブロックを使用していることに気付いたかもしれません。その場合、パターンには1(「true」)が想定されるため、レコードごとにアクションブロックが実行されます。

ニーズによっては、空白行または空白のみの行に必要なものが生成されない場合があります。その場合、その2番目のバージョンの方が少し優れている可能性があります:

awk 'NF { print $1, $3 }' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
        ,
17,abhishek

どちらの場合も、FSのカスタム値を渡しました およびOFS コマンドラインで。別のオプションは、特別なBEGINを使用することです。 AWKプログラム内でブロックして、最初のレコードが読み取られる前にこれらの変数を初期化します。したがって、好みによっては、代わりに次のように書くことをお勧めします。

awk 'BEGIN { FS=OFS="," } NF { print $1, $3 }' file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
        ,
17,abhishek

ここで言及する価値があるのは、ENDを使用することもできます 最後のレコードが読み取られた後にいくつかのタスクを実行するためのブロック。私たちが今それを見るように。そうは言っても、空白のみの線はエレガントに処理されないため、これは完璧にはほど遠いことを認めます。すぐに可能な解決策が見つかりますが、その前にいくつかの計算を行いましょう…

7。列ごとに計算を実行する

AWKは標準の算術演算子をサポートしています。また、コンテキストに応じて、テキストと数値の間で値を自動的に変換します。また、独自の変数を使用して中間値を格納することもできます。データ列の計算を実行するコンパクトなプログラムを作成できるようにするすべてのこと:

awk '{ SUM=SUM+$1 } END { print SUM }' FS=, OFS=, file
263

または、同等に+=を使用します 省略構文:

awk '{ SUM+=$1 } END { print SUM }' FS=, OFS=, file
263

AWK変数は使用前に宣言する必要がないことに注意してください。未定義の変数は、空の文字列を保持していると見なされます。これは、AWK型変換規則によれば、0の数値に等しくなります。その機能のために、私は$1の場合を明示的に処理する必要はありませんでした テキスト(見出し内)、空白、または何も含まれていません。これらすべての場合において、それは0としてカウントされ、合計に干渉しません。もちろん、代わりに乗算を実行した場合は異なります。では、なぜその場合の解決策を提案するためにコメントセクションを使用しないのですか?

8。空でない行の数を数える

ENDについてはすでに説明しました 前のルール。ファイル内の空でない行の数をカウントする別の可能なアプリケーションは次のとおりです。

awk '/./ { COUNT+=1 } END { print COUNT }' file
9

ここではCOUNTを使用しました 変数と増分(+=1 )正規表現/./に一致する各行 。つまり、各行には少なくとも1つの文字が含まれています。最後に、ファイル全体が処理された後、ENDブロックを使用して最終結果を表示します。 COUNTという名前には特別なことは何もありません 。 Countを使用できたはずです 、countnxxxx またはAWK変数の命名規則に準拠するその他の名前

しかし、この結果は正しいですか?まあ、それはあなたの「空の」線の定義に依存します。 (POSIXによる)空白行のみが空であると考える場合、これは正しいです。しかし、空白のみの行も空であると見なしたいですか?

awk 'NF { COUNT+=1 } END { print COUNT }' file
8

今回は、後のバージョンでは空白のみの行も無視されるのに対し、初期バージョンでは空白行のみが無視されるため、結果は異なります。違いがわかりますか?私はあなたにそれを自分で理解させます。十分に明確でない場合は、コメントセクションを使用することを躊躇しないでください!

最後に、データ行のみに関心があり、特定の入力データファイルがあれば、代わりに次のように記述できます。

awk '+$1 { COUNT+=1 } END { print COUNT }' file
7

これは、AWK型変換ルールのために機能します。パターンの単項プラスは、数値コンテキストで$1の評価を強制します。私のファイルでは、データレコードの最初のフィールドに数字が含まれています。非データレコード(見出し、空白行、空白のみの行)には、テキストが含まれるか、何も含まれません。数値に変換すると、すべて0になります。

その最新のソリューションでは、最終的に0クレジットを持つユーザーのレコードも破棄されることに注意してください。

B。 AWKでのアレイの使用

アレイはAWKの強力な機能です。 AWKのすべての配列は連想配列であるため、任意の文字列を別の値に関連付けることができます。他のプログラミング言語に精通している場合は、それらを hashes として知っているかもしれません。 連想テーブル 辞書 またはマップ

9。 AWKアレイの簡単な例

すべてのユーザーの合計クレジットを知りたいとしましょう。各ユーザーのエントリを連想配列に格納でき、そのユーザーのレコードに遭遇するたびに、配列に格納されている対応する値をインクリメントします。

awk '+$1 { CREDITS[$3]+=$1 }
     END { for (NAME in CREDITS) print NAME, CREDITS[NAME] }' FS=, file
abhishek 17
sonia 129
öle 8
sylvain 109

私はこれがもはやワンライナーではないことを認めます。主な理由はfor ファイルが処理された後に配列の内容を表示するために使用されるループ。それでは、短い例に戻りましょう:

10。 AWKを使用した重複行の識別

配列は、他のAWK変数と同様に、アクションブロックとパターンの両方で使用できます。それを利用することで、重複した行だけを印刷するワンライナーを書くことができます:

awk 'a[$0]++' file
52,01    dec   2018,sonia,team

++ 演算子は、C言語ファミリから継承されたインクリメント後の演算子です(Brian Kernighanが元の作成者の1人であったおかげで、AWKは誇り高いメンバーです)。

その名前が示すように、ポストインクリメント演算子は変数をインクリメント(「1を加算」)しますが、その値がエングロビン式の評価に使用された後でのみです。

その場合、a[$0] レコードが印刷されるかどうかを確認するために評価され、決定が行われると、すべての場合で、配列エントリがインクリメントされます。

したがって、レコードを初めて読み取るときは、a[$0] は未定義であるため、AWKの場合はゼロに相当します。そのため、最初のレコードは出力に書き込まれません。次に、そのエントリが0から1に変更されます。
同じ入力レコードが2回目に読み取られるときは、a[$0] 今は1です。それは「本当」です。行が印刷されます。ただし、その前に、配列エントリが1から2に更新されます。

11。重複する行を削除する

以前のワンライナーの結果として、重複する行を削除したい場合があります:

awk '!a[$0]++' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support


17,05 apr 2019,abhishek,guest

唯一の違いは、演算子ではなく論理の使用です(! )式の真​​理値を逆にします。偽りが真になり、真が偽りになります。論理は++にまったく影響を与えません 以前とまったく同じように機能するポストインクリメント。

C。フィールドとレコードの区切り文字の魔法

12。フィールドセパレータの変更

awk '$1=$1' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support

17;05 apr 2019;abhishek;guest

そのプログラムはFSを設定します およびOFS 入力フィールドセパレータとしてコマを使用し、出力フィールドセパレータとしてセミコロンを使用する変数。フィールドを変更しない限り、AWKは出力レコードを変更しないため、$1=$1 トリックは、AWKにレコードを強制的に破壊し、出力フィールドセパレーターを使用して再アセンブルするために使用されます。

ここで、デフォルトのアクションブロックは{ print }であることを忘れないでください 。したがって、これをより明示的に次のように書き直すことができます。

awk '$1=$1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support

17;05 apr 2019;abhishek;guest

これらの例の両方で空の行も削除されていることに気付いたかもしれません。なんで? AWK変換ルールを覚えておいてください。空の文字列は「false」です。他のすべての文字列は「真」です。式$1=$1 $1を変更する愛情です 。ただし、これも表現です。そして、$1の値に評価されます –これは空の文字列に対して「false」です。本当にすべての行が必要な場合は、代わりにそのようなものを書く必要があるかもしれません:

awk '($1=$1) || 1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support



17;05 apr 2019;abhishek;guest

&&を覚えていますか オペレーター?それは論理積でした。 || 論理ORです。演算子の優先順位規則のため、ここでは括弧が必要です。それらがなければ、パターンは誤って$1=($1 || 1)として解釈されていたでしょう。 代わりは。演習として、結果がどのように異なっていたかをテストします。

最後に、算術演算にあまり熱心でない場合は、もっと簡単な解決策を好むでしょう:

awk '{ $1=$1; print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support



17;05 apr 2019;abhishek;guest

13。複数のスペースを削除する

awk '$1=$1' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest

これは前のプログラムとほとんど同じプログラムです。ただし、フィールドセパレータはデフォルト値のままにしました。したがって、入力フィールドの区切り文字として複数の空白が使用されますが、出力フィールドの区切り文字として使用されるスペースは1つだけです。これには、倍数を合体させるという優れた副作用があります。 oneへの空白 スペース。

14。 AWKを使用してラインを結合する

すでにOFSを使用しています 、出力フィールドセパレータ。ご想像のとおり、ORSがあります 出力レコード区切り文字を指定するための対応物:

awk '{ print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle    abhishek

ここでは、改行文字の代わりに、各レコードの後に​​スペースを使用しました。このワンライナーは、一部のユースケースでは十分ですが、それでもいくつかの欠点があります。

最も明らかに、空白のみの行(öleの後の余分なスペース)は破棄されません。 それから来ています)。したがって、代わりに単純な正規表現を使用することになります。

awk '/[^[:space:]]/ { print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle abhishek

今は良くなっていますが、まだ問題があります。セパレータを目に見えるものに変更すると、より明確になります:

awk '/[^[:space:]]/ { print $3 }' FS=, ORS='+' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek+

行の終わりに余分な区切り文字があります—フィールド区切り記号はと書かれているためです。 各レコード。最後のものを含む。

これを修正するために、プログラムを書き直して、カスタムセパレータをに表示します。 2番目の出力レコードから始まるレコード。

awk '/[^[:space:]]/ { print SEP $3; SEP="+" }' FS=, ORS='' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek

区切り文字は自分で追加するので、標準のAWK出力レコード区切り文字も空の文字列に設定します。ただし、区切り文字や書式設定を使い始めるときは、printfの使用を検討する必要がある兆候かもしれません。 printの代わりに関数 声明。これから見ていきます。

D。フィールドフォーマット

AWKとCプログラミング言語の関係についてはすでに説明しました。特に、C言語の標準ライブラリからAWKは強力なprintfを継承しています。 この機能により、出力に送信されるテキストのフォーマットを細かく制御できます。

printf 関数は最初の引数としてフォーマットを取り、逐語的に出力されるプレーンテキストと出力の異なるセクションをフォーマットするために使用されるワイルドカードの両方を含みます。ワイルドカードは%で識別されます キャラクター。最も一般的なのは%s (文字列フォーマットの場合)、%d (整数フォーマットの場合)および%f (浮動小数点数のフォーマット用)。これはかなり抽象的である可能性があるため、例を見てみましょう。

awk '+$1 { printf("%s ",  $3) }' FS=, file; echo
sylvain sonia sonia sonia sylvain öle abhishek

printの反対として、お気づきかもしれません。 ステートメント、printf 関数はOFSを使用しません およびORS 値。したがって、区切り文字が必要な場合は、フォーマット文字列の最後にスペース文字を追加して、私が行ったように明示的に言及する必要があります。これは、出力を完全に制御するために支払う代償です。

フォーマット指定子ではありませんが、これは\nを紹介する絶好の機会です。 改行文字を表すために任意のAWK文字列で使用できる表記法。

awk '+$1 { printf("%s\n",  $3) }' FS=, file
sylvain
sonia
sonia
sonia
sylvain
öle
abhishek

15。表形式の結果を生成する

AWKは、区切り文字に基づいてレコード/フィールドデータ形式を適用します。ただし、printfを使用する 関数を使用すると、固定幅の表形式の出力を生成することもできます。 printfの各フォーマット指定子は ステートメントはオプションの幅パラメータを受け入れることができます:

awk '+$1 { printf("%10s | %4d\n",  $3, $1) }' FS=, file
   sylvain |   99
     sonia |   52
     sonia |   52
     sonia |   25
   sylvain |   10
       öle |    8
  abhishek |   17

ご覧のとおり、各フィールドの幅を指定することにより、AWKはフィールドの左側にスペースを埋め込みます。テキストの場合、通常は右側にパディングすることをお勧めします。これは、負の幅の数値を使用して実現できます。また、整数の場合、スペースの代わりにゼロでフィールドを埋めたい場合があります。これは、フィールド幅の前に明示的な0を使用することで取得できます:

awk '+$1 { printf("%-10s | %04d\n",  $3, $1) }' FS=, file
sylvain    | 0099
sonia      | 0052
sonia      | 0052
sonia      | 0025
sylvain    | 0010
öle        | 0008
abhishek   | 0017

16。浮動小数点数の処理

%f フォーマットは多くの説明に値しません…

awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%f",SUM/NUM); }' FS=, file
AVG=37.571429

…ほとんどの場合、表示される結果のフィールド幅と精度を明示的に設定する必要があると言う場合を除きます。

awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%6.1f",SUM/NUM); }' FS=, file
AVG=  37.6

ここで、フィールド幅は6です。これは、フィールドが6文字のスペースを占めることを意味します(ドットを含み、最終的には通常どおり左側にスペースが埋め込まれます)。 .1の精度は、ドットの後に10進数の1を含む数値を表示することを意味します。 %06.1が何であるかを推測させます 代わりに表示されます。

E。 AWKでの文字列関数の使用

printfに加えて 関数、AWKには他のいくつかの素晴らしい文字列操作関数が含まれています。そのドメインでは、Gawkのような最新の実装には、移植性が低くなる代わりに、より豊富な内部機能のセットがあります。私自身は、どこでも同じように機能するPOSIX定義の関数をいくつか使用します。

17。テキストを大文字に変換する

これは、国際化の問題をうまく処理するため、よく使用します。

awk '$3 { print toupper($0); }' file
99,01 JUN 2018,SYLVAIN,TEAM:::ADMIN
52,01    DEC   2018,SONIA,TEAM
52,01    DEC   2018,SONIA,TEAM
25,01    JAN   2019,SONIA,TEAM
10,01 JAN 2019,SYLVAIN,TEAM:::ADMIN
8,12    JUN   2018,ÖLE,TEAM:SUPPORT
17,05 APR 2019,ABHISHEK,GUEST

実際のところ、これはおそらく、シェルからテキストを大文字に変換するための最良かつ最も移植性の高いソリューションです。

18。文字列の一部を変更する

substrを使用する コマンドを使用すると、文字列を特定の長さに分割できます。ここでは、3番目のフィールドの最初の文字のみを大文字にするために使用します:

awk '{ $3 = toupper(substr($3,1,1)) substr($3,2) } $3' FS=, OFS=, file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,Sylvain,team:::admin
52,01    dec   2018,Sonia,team
52,01    dec   2018,Sonia,team
25,01    jan   2019,Sonia,team
10,01 jan 2019,Sylvain,team:::admin
8,12    jun   2018,Öle,team:support
17,05 apr 2019,Abhishek,guest

substr 関数は、最初の文字列、抽出する最初の文字の(1ベースの)インデックス、および抽出する文字数を受け取ります。最後の引数が欠落している場合は、substr 文字列の残りのすべての文字を取得します。

したがって、substr($3,1,1) $3の最初の文字に評価されます 、およびsubstr($3,2) 残りのものに。

19。サブフィールドでのフィールドの分割

AWKレコードフィールドデータモデルは本当に素晴らしいです。ただし、内部セパレータに基づいてフィールド自体をいくつかの部分に分割したい場合があります。

awk '+$1 { split($2, DATE, " "); print $1,$3, DATE[2], DATE[3] }' FS=, OFS=, file
99,sylvain,jun,2018
52,sonia,dec,2018
52,sonia,dec,2018
25,sonia,jan,2019
10,sylvain,jan,2019
8,öle,jun,2018
17,abhishek,apr,2019

やや意外なことに、これは、一部のフィールドが複数の空白で区切られている場合でも機能します。主に歴史的な理由から、区切り文字が単一のスペースの場合、split 「要素は空白の実行によって分離されている」と見なされます。そして、1つだけではありません。 FS 特別な変数は同じ規則に従います。

ただし、一般的な場合、1文字の文字列は1文字と一致します。したがって、より複雑なものが必要な場合は、フィールド区切り文字が拡張正規表現であることを覚えておく必要があります。

例として、コロンを区切り文字として使用して、複数値のフィールドのように見えるグループフィールドがどのように処理されるかを見てみましょう。

awk '+$1 { split($4, GRP, ":"); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team
sonia team
sonia team
sonia team
sylvain team
öle team support
abhishek guest

ユーザーごとに最大2つのグループを表示すると予想していましたが、ほとんどのグループでは1つしか表示されません。この問題は、セパレータが複数回発生することが原因で発生します。したがって、解決策は次のとおりです。

awk '+$1 { split($4, GRP, /:+/); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team admin
sonia team
sonia team
sonia team
sylvain team admin
öle team support
abhishek guest

引用符の代わりにスラッシュは、リテラルがプレーンな文字列ではなく正規表現であることを示し、プラス記号は、この式が前の文字の1つまたは複数のオカレンスと一致することを示します。したがって、その場合、各セパレーターは(最長のシーケンスで)1つまたは複数の連続したコロンで構成されます。

20。 AWKコマンドの検索と置換

正規表現と言えば、sed s///gのような置換を実行したい場合があります。 コマンドですが、1つのフィールドのみです。 gsub その場合に必要なのはコマンドです:

awk '+$1 { gsub(/ +/, "-", $2); print }' FS=, file
99 01-jun-2018 sylvain team:::admin
52 01-dec-2018 sonia team
52 01-dec-2018 sonia team
25 01-jan-2019 sonia team
10 01-jan-2019 sylvain team:::admin
8 12-jun-2018 öle team:support
17 05-apr-2019 abhishek guest

gsub 関数は、検索する正規表現、置換文字列、および変更するテキストを含む変数を受け取ります。後でそれが欠落している場合は、$0が想定されます。

F。 AWKでの外部コマンドの操作

AWKのもう1つの優れた機能は、外部コマンドを簡単に呼び出してデータを処理できることです。これを行うには、基本的に2つの方法があります。systemを使用する プログラムを呼び出して、その出力をAWK出力ストリームに混合させる命令。または、パイプを使用して、AWKが外部プログラムの出力をキャプチャして結果をより細かく制御できるようにします。

これらはそれ自体が大きなトピックかもしれませんが、これらの機能の背後にある力を示す簡単な例をいくつか示します。

21。ファイルの上に日付を追加する

awk 'BEGIN { printf("UPDATED: "); system("date") } /^UPDATED:/ { next } 1' file
UPDATED: Thu Feb 15 00:31:03 CET 2018
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

そのAWKプログラムでは、まず作品UPDATEDを表示します。次に、プログラムは外部のdateを呼び出します コマンド。その段階でAWKによって生成されたテキストの直後に結果を出力に送信します。
AWKプログラムの残りの部分は、ファイルに最終的に存在する更新ステートメントを削除し、他のすべての行を出力します(ルール1

nextに注目してください 声明。現在のレコードの処理を中止するために使用されます。 It is a standard way of ignoring some records from the input file.

22. Modifying a field externally

For more complex cases, you may need to consider the | getline VARIABLE idiom of AWK:

awk '+$1 { CMD | getline $5; close(CMD); print }' CMD="uuid -v4" FS=, OFS=, file
99,01 jun 2018,sylvain,team:::admin,5e5a1bb5-8a47-48ee-b373-16dc8975f725
52,01    dec   2018,sonia,team,2b87e9b9-3e75-4888-bdb8-26a9b34facf3
52,01    dec   2018,sonia,team,a5fc22b5-5388-49be-ac7b-78063cbbe652
25,01    jan   2019,sonia,team,3abb0432-65ef-4916-9702-a6095f3fafe4
10,01 jan 2019,sylvain,team:::admin,592e9e80-b86a-4833-9e58-1fe2428aa2a2
8,12    jun   2018,öle,team:support,3290bdef-fd84-4026-a02c-46338afd4243
17,05 apr 2019,abhishek,guest,e213d756-ac7f-4228-818f-1125cba0810f

This will run the command stored in the CMD variable, read the first line of the output of that command, and store it into the variable $5

Pay special attention to the close statement, crucial here as we want AWK to create a new instance of the external command each time it executes the CMD | getline statement. Without the close statement, AWK would instead try to read several lines of output from the same command instance.

23. Invoking dynamically generated commands

Commands in AWK are just plain strings without anything special. It is the pipe operator that triggers external programs execution. So, if you need, you can dynamically construct arbitrary complex commands by using the AWK string manipulation functions and operators.

awk '+$1 { cmd = sprintf(FMT, $2); cmd | getline $2; close(cmd); print }' FMT='date -I -d "%s"'  FS=, file
99 2018-06-01 sylvain team:::admin
52 2018-12-01 sonia team
52 2018-12-01 sonia team
25 2019-01-01 sonia team
10 2019-01-01 sylvain team:::admin
8 2018-06-12 öle team:support
17 2019-04-05 abhishek guest

We have already met the printf 働き。 sprintf is very similar but will return the built string rather than sending it to the output.

24. Joining data

To show you the purpose of the close statement, I let you try out that last example:

awk '+$1 { CMD | getline $5; print }' CMD='od -vAn -w4 -t x /dev/urandom' FS=, file
99 01 jun 2018 sylvain team:::admin  1e2a4f52
52 01    dec   2018 sonia team  c23d4b65
52 01    dec   2018 sonia team  347489e5
25 01    jan   2019 sonia team  ba985e55
10 01 jan 2019 sylvain team:::admin  81e9a01c
8 12    jun   2018 öle team:support  4535ba30
17 05 apr 2019 abhishek guest  80a60ec8

As the opposite of the example using the uuid command above, there is here only one instance of od launched while the AWK program is running, and when processing each record, we read one more line of the output of that same process.

結論

That quick tour of AWK certainly can’t replace a full-fledged course or tutorial on that tool. However, for those of you that weren’t familiar with it, I hope it gave you enough ideas so you can immediately add AWK to your toolbox.

On the other hand, if you were already an AWK aficionado, you might have found here some tricks you can use to be more efficient or simply to impress your friends.

However, I do not pretend been exhaustive. So, in all cases, don’t hesitate to share your favorite AWK one-liner or any other AWK tips using the comment section below!


Linux
  1. Zshの使用を開始する

  2. Linuxtacコマンドの使用を開始する

  3. Linuxcatコマンドの使用を開始する

  1. lsの使用を開始する

  2. LinuxでPostgreSQLを使い始める

  3. マルチパス入門–UbuntuVMの実行

  1. GnuCashの使用を開始する

  2. 強力なテキスト解析ツールであるawkの使用を開始する

  3. Etcher.ioを使い始める