最初の列の文字列が前の行の最初の列の文字列と異なる場合は、前の行全体を印刷する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に割り当てます。
変数l1
sumは、最初のフィールド()と行全体()を保持l0
するために使用されます。$1
$0
ほとんどの場合、awk
スクリプトは一連のPATTERN { ACTION }
ルールです。 PATTERN が true と評価されると、ACTION が実行されます。 PATTERN は、true または false と評価されるすべての項目 (正規表現の一致、変数の比較、計算など) にすることができます。 ACTIONは任意のawkコードステートメントです。これらのルールは各入力行に対して繰り返されます。 PATTERNまたはACTIONはオプションです。 PATTERNが見つからない場合はtrueと評価され、ACTIONは常に実行されます。 ACTIONが欠落している場合、デフォルトの動作はprint
(つまり、現在の入力行の印刷)です。これは非常に単純で簡略化された要約です。詳細については、awkのドキュメントを参照してください(たとえば、man awk
GNU awkを使用している場合はinfo awk
O'Reillyも参照)。sedとawkDale DoughertyとArnold Robbinsの本)。
awkスクリプトの最初の行は、現在の行が次のようになるかどうかをテストします$1
。等しくない両方l1
そして空の文字列。両方のテストがtrueの場合は、最後の入力行を印刷しますl0
。入力の最初の行はl1
常に空なので(スクリプトの2行目はまだ実行されていないため、まだ値が割り当てられていないため)何も印刷されません(l0
とにかく空です)。 (印刷する場合は空行のみ出力されます。)
awkスクリプトの2行目は、無条件に現在の入力行の合計を設定しますl1
。l0
スクリプトは各入力行に対してこの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つのライナーを置き換えます。。 「各グループの最後の値」を参照してください。