sedを使用してCSVの特定の列の内容を置き換える

sedを使用してCSVの特定の列の内容を置き換える

複数のCSVログファイルがあり、このログファイルの列8に格納されているステータスコードを説明に置き換えたいと思います。

ログファイルは次のとおりです。

ip,date,time,zone,cik,accession,extention,code,size,idx,norefer,noagent,find,crawler,browser
101.xx.xxx.xx,2017-06-23,00:00:00,0.0,1238039.0,0001179110-17-009492,calc.xml,301.0,654.0,0.0,0.0,0.0,10.0,0.0,
101.xx.xxx.xx,2017-06-25,00:00:00,0.0,793347.0,0000798086-17-000026,index.htm,200.0,31791.0,1.0,0.0,0.0,9.0,0.0,
101.xx.xxx.xx,2017-06-28,00:00:00,0.0,918537.0,0001209191-17-041401,index.htm,200.0,9936.0,1.0,0.0,0.0,9.0,0.0,

私が達成したい結果は次のとおりです。

101.xx.xxx.xx,2017-06-23,00:00:00,0.0,1238039.0,0001179110-17-009492,calc.xml,MOVED PERMANENTLY,654.0,0.0,0.0,0.0,10.0,0.0,
101.xx.xxx.xx,2017-06-25,00:00:00,0.0,793347.0,0000798086-17-000026,index.htm,OK,31791.0,1.0,0.0,0.0,9.0,0.0,
101.xx.xxx.xx,2017-06-28,00:00:00,0.0,918537.0,0001209191-17-041401,index.htm,OK,9936.0,1.0,0.0,0.0,9.0,0.0,

私のコードは現在次のとおりですが、必要に応じて列8にアクセスしません。

 sed -r 's/^(([^,]*,){7})/200.0/OK/;s/206.0/PARTIAL CONTENT/;s/301.0/MOVED PERMANENTLY/;s/304.0/NOT MODIFIED/;s/400.0/BAD REQUEST/;s/403.0/FORBIDDEN/;s/404.0/NOT FOUND/;s/429.0/TOO MANY REQUESTS/;s/500.0/INTERNAL SERVER ERROR/;s/502.0/BAD GATEWAY/;s/503.0/SERVICE UNAVAILABLE/;s/504.0/GATEWAY TIMEOUT/'

列8のコードを置き換えるには、私のコードをどのように修正しますか?

編集する:非常に薄暗い解決策ですが、うまくいきます。

 sed -r 'h; s/^(([^,]*,){7}).*/\1/; x; s/^(([^,]*,){7})//; s/200.0/OK/;s/206.0/PARTIAL CONTENT/;s/301.0/MOVED PERMANENTLY/;s/304.0/NOT MODIFIED/;s/400.0/BAD REQUEST/;s/403.0/FORBIDDEN/;s/404.0/NOT FOUND/;s/429.0/TOO MANY REQUESTS/;s/500.0/INTERNAL SERVER ERROR/;s/502.0/BAD GATEWAY/;s/503.0/SERVICE UNAVAILABLE/;s/504.0/GATEWAY TIMEOUT/; H; x; s/\n//'

ベストアンサー1

これを行う最善の方法は、ルックアップテーブルを使用することです。代わりにawkorのようなものを使うことです。たとえば、perlsed

awk '
  BEGIN {
    FS=OFS=",";
    codes[200] = "OK";
    codes[206] = "PARTIAL CONTENT";
    codes[301] = "MOVED PERMANENTLY";
    codes[304] = "NOT MODIFIED";
    codes[400] = "BAD REQUEST";
    codes[403] = "FORBIDDEN";
    codes[404] = "NOT FOUND";
    codes[429] = "TOO MANY REQUESTS";
    codes[500] = "INTERNAL SERVER ERROR";
    codes[502] = "BAD GATEWAY";
    codes[503] = "SERVICE UNAVAILABLE";
    codes[504] = "GATEWAY TIMEOUT";
  };
  FNR == 1 { next };   # skip header line
  { c = $8+0; if (c in codes) { $8 = codes[c] } };
  1
' log.csv
101.xx.xxx.xx,2017-06-23,00:00:00,0.0,1238039.0,0001179110-17-009492,calc.xml,MOVED PERMANENTLY,654.0,0.0,0.0,0.0,10.0,0.0,
101.xx.xxx.xx,2017-06-25,00:00:00,0.0,793347.0,0000798086-17-000026,index.htm,OK,31791.0,1.0,0.0,0.0,9.0,0.0,
101.xx.xxx.xx,2017-06-28,00:00:00,0.0,918537.0,0001209191-17-041401,index.htm,OK,9936.0,1.0,0.0,0.0,9.0,0.0,

$8+0awkが8番目のフィールドを数値として評価すると、不要なフィールドが削除されます。.0ログファイルにHTTP結果コードの浮動小数点がある理由はわかりませんが、ファイルにこのような内容がある場合は、次の手順を実行する必要があります。処理のためになければなりません。インデックスを包括的に作成してこれを実行できます.0。私は整数値を使用することを好みます。

フィールド8のコード番号がわからない場合は、変更せずに残してください。それ以外の場合は、配列の対応する値に置き換えられますcodes


ちなみに、各行の末尾にあるセミコロンはawkでオプションであり、1行に複数の文がある場合にのみ必要です。必要に応じて、スクリプト全体を読み取れないほど長い1行に圧縮できるようにそこに残しました。一部の人々はこれが好きです。理由はわかりません。多分マゾヒズムかもしれません。実際のスクリプトをファイルとして保存し、1行を使用またはawk -f実行する方が良いと思います#!/usr/bin/awk -f


また、HTTPレスポンスコードのテーブル全体を含むファイルやWebページを見つけることも難しくありません。テキストファイルに保存し、適切な形式(numeric-code<tab>description例:)で編集し、awkスクリプトが入力ファイルの前にファイルを読み取り、BEGINにハードコーディングする代わりに配列に保存することは難しくありません。 block 配列をエンコードします。テーブルは頻繁に変更されないので、気にする価値はないようですが...単純なルックアップテーブルを必要とする他の作業では注意する必要があります。


最後に、これはPerlバージョンです。これは以下を使用します。HTTP::状態ライブラリモジュールのHTTP::メッセージすべてのHTTPステータスコードがすでに含まれているライブラリのコレクション。

$ perl -MHTTP::Status -F, -lane '
  next if $. == 1;                # skip header line
  $msg = status_message($F[7]+0); # perl arrays start from 0, not 1
  $F[7] = uc($msg) if $msg;       # uc() to all-caps the msg
  print join(",",@F);
  close(ARGV) if eof' log.csv 
101.xx.xxx.xx,2017-06-23,00:00:00,0.0,1238039.0,0001179110-17-009492,calc.xml,MOVED PERMANENTLY,654.0,0.0,0.0,0.0,10.0,0.0
101.xx.xxx.xx,2017-06-25,00:00:00,0.0,793347.0,0000798086-17-000026,index.htm,OK,31791.0,1.0,0.0,0.0,9.0,0.0
101.xx.xxx.xx,2017-06-28,00:00:00,0.0,918537.0,0001209191-17-041401,index.htm,OK,9936.0,1.0,0.0,0.0,9.0,0.0

awkの代わりにPerlを使用するもう1つの利点の1つは、「ホイールを再構築する」必要がないことに加えて、次のものを使用できることです。テキスト::CSV正しいCSVパーサー(つまり、引用符フィールドに含まれる引用符とコンマを処理できるモジュール)のためのモジュールであり、出力が正しい形式のCSVであることを確認してください(必要に応じて引用符を使用してください)。

おすすめ記事