複数の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
これを行う最善の方法は、ルックアップテーブルを使用することです。代わりにawk
orのようなものを使うことです。たとえば、perl
sed
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+0
awkが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であることを確認してください(必要に応じて引用符を使用してください)。
答え2
この試み:
sed -r 's/^(([^,]*,){7})200\.0/\1OK/;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/'
唯一の変更は、/200.0/
文字の代わりに200\.0/\1
ピリオドをテストし、逆参照「\ 1」を使用することです。おそらく、他の応答コード(206.0以降)がこの行の前にテキストとして表示されていないと確信できますか(206.0はIPアドレスの一部である可能性があります...)?\.
.
よりエレガントなツールのような他のツールを使用して実行できますが、awk
これはあなたのニーズに適しており、すでに持っているツールに基づいて構築されると思います。