awk - $1 列が前の $1 列と等しくない場合は、前の行全体を印刷します。

awk - $1 列が前の $1 列と等しくない場合は、前の行全体を印刷します。

最初の列の文字列が前の行の最初の列の文字列と異なる場合は、前の行全体を印刷するawkプログラムをLinuxで作成しようとしています。

別のアプローチは、最初の列が同じであるときはいつでも、一致する列の最後の行全体を印刷し、以前の同じ列を削除することです。

私は次のコードを使用しました。

awk 'BEGIN { FS=OFS=";" } $1==last{next} {last=$1} {print last}' test.txt

しかし、前の行の最初の列だけを印刷していると思います。前の行全体を印刷するには?

私の入力ファイルはtest.txt次のとおりです。

818522;"Joey";
817399;"john";
817399;"CCE";
817399;"smith";
817399;"Ron";
817400;
817400;
817400;
818000;"ODC";
890021;
890021;
890021;"rachel";
890021;"monica"

希望の出力:

818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";
890021;"monica"

答え1

あなたの説明が出力と一致しないため、少し混乱しています。あなたの説明によると、予想される出力は次のとおりです。

818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";

890021最後の行なので、どの行も印刷しないので、最初のフィールドは次の行と変わりません。これが本当に欲しいものなら、次のようにすることができます。

$ awk -F';' '{ 
                if($1!=last && prevLine){ print prevLine } 
                { last=$1; prevLine=$0 }
             }' file
818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";

最後の行にも例外を追加するには、以下を試してください。

$ awk -F';' '{ 
              if($1!=last && prevLine){
                print prevLine; 
                lastPrinted=last
              } 
              {
                last=$1; 
                prevLine=$0
              }
             }
             END{ 
                if($1 != lastPrinted){ print }
             }' file 
818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";
890021;"monica"

lastアイデアはとても簡単です。最初のフィールドが定義された変数と異なる場合prevLine(最初の行を印刷しない)、前の行(prevLine)を印刷し、前の行の最初のフィールド(last)を変数に保存します。lastPrinted

次に、すべての行に対してlast最初のフィールドとprevLine現在の行を設定します。最後に、ファイルの終わりに達すると(END{})行の最初のフィールドが最後に印刷した最初のフィールド()と異なる場合は、その行を印刷しますlastPrinted

答え2

$ awk -F';' '$1 != l1 && l1 != "" { print l0 };
             {l1 = $1; l0 = $0};
             END {if ($1 != $l1) {print}}' test.txt 
818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";
890021;"monica"

この-F';'オプションは、awkの入力フィールド区切り文字(FS)をセミコロンに設定します。 awkは各入力行を自動的に分割FSし、フィールドを$ 1、$ 2、$ 3、....、$ nに割り当てます。

変数l1sumは、最初のフィールド()と行全体()を保持l0するために使用されます。$1$0

ほとんどの場合、awkスクリプトは一連のPATTERN { ACTION }ルールです。 PATTERN が true と評価されると、ACTION が実行されます。 PATTERN は、true または false と評価されるすべての項目 (正規表現の一致、変数の比較、計算など) にすることができます。 ACTIONは任意のawkコードステートメントです。これらのルールは各入力行に対して繰り返されます。 PATTERNまたはACTIONはオプションです。 PATTERNが見つからない場合はtrueと評価され、ACTIONは常に実行されます。 ACTIONが欠落している場合、デフォルトの動作はprint(つまり、現在の入力行の印刷)です。これは非常に単純で簡略化された要約です。詳細については、awkのドキュメントを参照してください(たとえば、man awkGNU awkを使用している場合はinfo awkO'Reillyも参照)。sedとawkDale DoughertyとArnold Robbinsの本)。

awkスクリプトの最初の行は、現在の行が次のようになるかどうかをテストします$1等しくない両方l1 そして空の文字列。両方のテストがtrueの場合は、最後の入力行を印刷しますl0。入力の最初の行はl1常に空なので(スクリプトの2行目はまだ実行されていないため、まだ値が割り当てられていないため)何も印刷されません(l0とにかく空です)。 (印刷する場合は空行のみ出力されます。)

awkスクリプトの2行目は、無条件に現在の入力行の合計を設定しますl1l0

スクリプトは各入力行に対してこの2行のコードを繰り返します。

入力がなくなったら、基本スクリプトループが終了し、END {...}ブロックが実行されます。現在の入力行(つまり、入力の最後の行)を印刷します。現時点では、$1 != l1リフレクション(およびいくつかの簡単なテスト)を使用している場合にのみ、そのテストなしでうまく機能できますEND {print}

答え3

$ mlr --csv --fs ';' -N --ragged unsparsify then tail -n 1 -g 1 file
818522;Joey;
817399;Ron;
817400;;
818000;ODC;
890021;monica;

これは以下を使用します。ミラーmlr)はデータを無題のCSVに読み込み、;フィールド区切り文字として機能します。入力により、各レコードは異なる数のフィールドを持つことができます。

まず、この操作を使用して、各レコードの存在しないフィールドにnull値を入力し、最初のフィールドにグループ化するunsparsifyときtailに各グループの最後の値を取得します。

必要に応じて、出力に引用符を追加するか、--quote-allすべてのフィールドに引用符を追加できます。

答え4

使用datamash:

$ datamash -t ';' -g 1 last 2 <file

-t ;フィールド区切り記号でセミコロンを設定します。

last 2フィールド 2 の最後の値を印刷します。

-g 1例の略語ですgroupby 1

このコマンドは、以下から取得されます。Datamashは1つのライナーを置き換えます。。 「各グループの最後の値」を参照してください。

関連情報