Bashで「_」に基づいて列を分割する

Bashで「_」に基づいて列を分割する

こんにちは、私も同様の問題があります郵便はがき

しかし、私は初めてBashに触れてファイルが少し異なるので、答えを修正してコードに適用することはできません。

複数の列(カンマで区切られたすべての列)を持つcsvファイルがあり、分割したい列は次のとおりです。 (入力ファイル)

post_id
86680728811_272953252761568
 86680728811_273859942672742
86680728811_281125741936891
86680728811_10150500662053812
_86680728811_10150500969563812
86680728811_10150501303143812
86680728811_305275689511038
_86680728811_10150501624593812
 86680728811_10150501873973812
86680728811_145945585518261

2番目のID番号(下線の後の番号)を抽出したいと思います。一部の列は数字で始まり、一部は空白で始まり、一部は「_」で始まることに注意してください。

私が望む出力は、それぞれ「_」で区切られたIDを含む2つの新しい列を追加することです。最初の行の例:

page ID             post ID 
86680728811         272953252761568

正規表現を使用して数字を読み取ろうとします。

awk -F',' '{print $2} /(?<=_)[0-9]+/' FB_Dataset.csv

しかし、これまで試したことはすべてうまくいきません。どんな提案でも役に立ちます。ありがとう

答え1

awk -F', *_?' -v OFS=, '
  NR==1 {
    for (i=1;i<=NF;i++) {
      if ($i == "post_id") {
        $i = "page ID" OFS "post ID";
        col=$1;
      };
    };
    print;
    next
  };

  {
    split($col,a,/_/);
    $col=a[1] OFS a[2];
    print;
  };
  ' FB_Dataset.csv

表示されているフィールドデータが一貫性のない形式(一部はスペースで始まり、一部はアンダースコアで始まり、一部は両方)であるため、このawkスクリプトは正規表現, *_?(「カンマの後に0個以上のスペースが続き、オプションで後にスペースが続く」)アンダースコア ") をフィールド区切り記号 ( FS) として使用します。

また、出力フィールド区切り記号(OFS)をコンマに設定します。

入力を読み取ると、最初の行(CSVヘッダー)と残りのすべての行が異なるように処理されます。

最初の行(NR==1)では、各フィールドの値を調べて文字列を見つけます"post_id"。文字列が見つかったら、フィールド値を変更して、2つの新しいフィールド名(page IDおよびpost ID)と後で使用できるように、OFSフィールドのインデックス番号を変数に保存します。col最後に変更された行を印刷します。

これは、有効なCSVファイルのフィールド名が一意であることを前提としています。複数のフィールドに名前があると正しく機能しませんpost_id

残りの行では、$col下線()文字を区切り文字として使用してフィールドを配列に分割します。次に、$ colを配列の最初の2つの要素に置き換えて、変更された行を印刷します。a_OFS

入力例:

A,B,C,post_id,D,E,F
a,b,c,86680728811_272953252761568,d,e,f
a,b,c, 86680728811_273859942672742,d,e,f
a,b,c,86680728811_281125741936891,d,e,f

出力例:

A,B,C,page ID,post ID,D,E,F
a,b,c,86680728811,272953252761568,d,e,f
a,b,c,86680728811,273859942672742,d,e,f
a,b,c,86680728811,281125741936891,d,e,f

ヘッダー行では、このフィールドは2つのフィールド(および)post_idに変換され、CSVデータではそのフィールドが2つのフィールドに分割されました。page IDpost ID

ただし、スクリプトはpost_idヘッダー行で一致するフィールド名()を取得するため、分割したいフィールドの前後のフィールド数に関係なく処理できます。このサンプルデータを使用して、4番目のフィールドに希望の名前が含まれていることを確認しました。col=4


$iそしてawk$colはシェルとは異なる意味を持ちます。

  • シェルでは、これは次の変数を意味します。名前はいi、そしてcol
  • ではawkインデックス番号が変数値と同じフィールドの値i(または変数col)」です。つまり、間接参照を介してフィールドにアクセスします。

    たとえば、if i=1thenは$i「フィールド1の値」を意味し、と同じです$1

    たとえば、フィールド番号に対して算術演算を実行する必要がある場合に便利です。 awk では、NF現在の入力行の最後のフィールドのインデックス番号を含む自動生成変数です。 so は$NF「最後のフィールドの値」を意味し、$(NF-1)「最後のフィールドの 2 番目のフィールドの値」などを意味します。

答え2

これはあなたに効果がありますか?私は次の形式を仮定します。

A B C post_id
a,b,c,86680728811_272953252761568
a,b,c, 86680728811_273859942672742
a,b,c,86680728811_281125741936891
a,b,c,86680728811_10150500662053812
a,b,c,_86680728811_10150500969563812
a,b,c,86680728811_10150501303143812
a,b,c,86680728811_305275689511038
a,b,c,_86680728811_10150501624593812
a,b,c, 86680728811_10150501873973812
a,b,c,86680728811_145945585518261

その後、コマンド

cat file | sed -Ee 's/(.*)post_id/\1page ID post I/' -e 's/,[_ ]/,/' -e 's/_/,/'

出力:

A B C page ID post ID
a,b,c,86680728811,272953252761568
a,b,c,86680728811,273859942672742
a,b,c,86680728811,281125741936891
a,b,c,86680728811,10150500662053812
a,b,c,86680728811,10150500969563812
a,b,c,86680728811,10150501303143812
a,b,c,86680728811,305275689511038
a,b,c,86680728811,10150501624593812
a,b,c,86680728811,10150501873973812
a,b,c,86680728811,145945585518261

-E拡張正規表現(GNU)を使用すると、グループをキャプチャできます。


ヘッダーを変更してpage ID post IDキャプチャの最初のグループ(.*)まで追加しpost_id、キャプチャされたグループに置き換えます\1page ID post ID

's/(.*)post_id/\1page ID post ID/'

_コンマの後の行から先頭のスペースとアンダースコアを削除し、単一のコンマで置き換えます。

sed 's/,[_ ]/,/'

最後に、アンダースコアを_カンマで置き換えます。

sed 's/_/,/'

不要なコマンドを削除しました。cut(これは私が試した他のコマンドを思い出させます。)

答え3

私は次を使うでしょう:

awk -F' *_?' '{ print $(NF-1), $NF }' infile

関連情報