여러 개의 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에서 선택 사항이며 한 줄에 여러 개의 명령문이 있는 경우에만 필요합니다. 원한다면 전체 스크립트를 읽을 수 없을 정도로 긴 한 줄로 압축할 수 있도록 거기에 남겨 두었습니다. 어떤 사람들은 이것을 좋아합니다. 이유는 모르겠습니다. 어쩌면 마조히즘일지도 모릅니다. 실제 스크립트를 파일로 저장하고 awk -f
한 줄을 사용하거나 사용하여 실행하는 것이 더 좋다고 생각합니다 #!/usr/bin/awk -f
.
또한 HTTP 응답 코드의 전체 테이블이 포함된 파일이나 웹 페이지를 찾는 것도 어렵지 않습니다. 텍스트 파일에 저장하고 적절한 형식( 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을 사용하는 것의 또 다른 이점 중 하나는 "바퀴를 다시 만들" 필요가 없다는 것 외에도 다음을 사용할 수 있다는 것입니다.텍스트::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
이것이 귀하의 요구에 적합하고 이미 가지고 있는 도구를 기반으로 구축될 것이라고 생각합니다.