2017-02-16 1 views
2

sed를 사용하여 조작하는 CSV 파일이 있습니다. 내가하고있는 일은 현재 YYYY-MM-DD HH : MM : SS를 IP 주소 다음의 5 번째 필드에 삽입하는 것입니다. 아래에서 볼 수 있듯이 각 값은 큰 따옴표로 묶고 각 CSV 열은 쉼표로 구분됩니다. sed 'N;s/","/","YYYY-MM-DD HH:MM:SS","/5' FILENAME 내가 5 필드 다음 날짜에 추가하고 :IP 주소 인 CSV 파일의 다섯 번째 필드 뒤에 SED를 사용하여 값 추가

"12345","","","None","192.168.2.1","qqq","000" 
"67890","ABC-1234-5678","9.9","Low","192.168.2.1","qqq","000" 

명령을 사용하여. 일반적으로이 방법이 효과적이지만, 보통 CSV 파일의 특정 값이 날짜를 다섯 번째 필드에 삽입하는이 값을 엉망으로 만듭니다. 이 문제를 해결하려면 다섯 번째 필드 다음에 날짜를 추가 할뿐만 아니라 다섯 번째 필드가 IP 주소인지 확인하는 방법은 무엇입니까?

최종 출력은 다음과 같아야합니다

"12345","","","None","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000" 
"67890","ABC-1234-5678","9.9","Low","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000" 

이는 AWK를 SED를 사용하여 수행되지 않고 방법으로 응답 해주십시오. 그리고 어떻게 날짜를 추가하기 전에 다섯 번째 필드도 IP 주소인지 확인할 수 있습니까?

+1

왜 awk을 사용할 수 없습니까? 그것은 훨씬 더 적합 할 것입니다. –

+0

$ 5가 IP 주소가 아닌 행에서 어떻게해야합니까? –

+1

CSV 파일은 얼마나 깨끗한가요? 주변에 큰 따옴표가없는 필드가 있습니까? ''... ""... "'문자열에 포함 된 큰 따옴표를 표시하는 필드가 있습니까? 따옴표 사이에 쉼표가있는 필드가 있습니까 (''this, that "')? 그것은 치명적인 것은 아니지만, 'YYYY-MM-DD HH : MM : SS'의 값은 변수 (예 :'date + '% Y- % m- % d % H : %의 출력) M : % S''이 캡쳐되어'sed' 명령으로 대체됩니까? –

답변

2

이 답변은되도록 CSV 파일 (샘플 데이터로) 아름답게 일관되고 간단 있다고 가정

  • 필드는 항상 큰 따옴표가있다.
  • 문자열에 포함 된 큰 따옴표를 나타내는 "…""…"과 같은 입력란은 절대로 존재하지 않습니다.
  • 따옴표 사이에는 쉼표가있는 입력란이 없습니다 ("this,that").

    sed 's/^\("[^"]*",\)\{4\}"\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}",/&"YYYY-MM-DD HH:MM:SS",/' 
    

    하는의 조각으로 해당 검색 패턴을 분할하자 : 라인의

    • ^\("[^"]*",\)\{4\}

      경기 시작

    • 그 전제 조건을 감안할 때

    sed 스크립트는 작업을 수행 뒤에 오는 것 : 큰 따옴표의 4 반복, 0 개 이상의 큰 따옴표의 순서, 두 배 따옴표와 쉼표.

    즉, 처음 네 개의 필드를 식별합니다.

  • "\([0-9]\{1,3\}\.\)\{3\}

    일치 따옴표

    후 뒤에 도트 1-3 진수의 3 개 반복 -는 IPv4의 처음 세 쌍둥이는 점으로 구분 된 십진수 주소를.따옴표와 쉼표

  • [0-9]\{1,3\}",

    경기 1-3 진수 -는 IPv4의 마지막 삼중는 점으로 구분 된 십진수 주소 플러스 필드의 끝을.

명확히 말하면, 처리해야하는 CSV 파일의 각 고유성에 대해 정규 표현식을 수정해야합니다. 그것은 사소한 것이 아닙니다. (GNU와 BSD sed 모두 -E으로 사용) 확장 된 정규 표현식을 사용

, 당신은 쓸 수 :

sed -E 's/^("(([^"]*"")*[^"]*)",){4}"([0-9]{1,3}\.){3}[0-9]{1,3}",/&"YYYY-MM-DD HH:MM:SS",/' 

처음 4 개 필드를 인식하는 패턴이 이전보다 더 복잡하다. 큰 따옴표, 두 개 이상의 큰 따옴표, 두 개 이상의 큰 따옴표, 두 개 이상의 큰 따옴표, 큰 따옴표 및 쉼표 순으로 4 번 반복됩니다. 데이터 파일을 감안할 때

sed 's/^\("\(\([^"]*""\)*[^"]*\)",\)\{4\}"\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}",/&"YYYY-MM-DD HH:MM:SS",/' 

가 :

"12345","","","None","192.168.2.1","qqq","000" 
"67890","ABC-1234-5678","9.9","Low","192.168.2.1","qqq","000" 
"23456","Quaternions","2.3","Pisces","Heredotus","qqq","000" 
"34567","Commas, oh commas!","3.14159","""Quotes"" quoth he","192.168.99.37","zzz","011" 
"45678","Commas, oh commas!","3.14159","""Quote me"",""or not""","192.168.99.37","zzz","011" 

표시되는 첫 번째 스크립트는 출력을 생성

또한 백 슬래시의 자유 뿌리 클래식 sed (기본 정규 표현식)의 것을 쓸 수 있습니다 :

"12345","","","None","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000" 
"67890","ABC-1234-5678","9.9","Low","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000" 
"23456","Quaternions","2.3","Pisces","Heredotus","qqq","000" 
"34567","Commas, oh commas!","3.14159","""Quotes"" quoth he","192.168.99.37","zzz","011" 
"45678","Commas, oh commas!","3.14159","""Quote me"",""or not""","192.168.99.37","zzz","011" 

첫 번째 두 줄은 올바르게 매핑됩니다. 에드; 세 번째는 바뀌지 않지만 마지막 두 개는 매핑되어 있어야하고 그렇지 않습니다. Heredotus이 (제대로) 수정되지 않습니다

"12345","","","None","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000" 
"67890","ABC-1234-5678","9.9","Low","192.168.2.1","YYYY-MM-DD HH:MM:SS","qqq","000" 
"23456","Quaternions","2.3","Pisces","Heredotus","qqq","000" 
"34567","Commas, oh commas!","3.14159","""Quotes"" quoth he","192.168.99.37","YYYY-MM-DD HH:MM:SS","zzz","011" 
"45678","Commas, oh commas!","3.14159","""Quote me"",""or not""","192.168.99.37","YYYY-MM-DD HH:MM:SS","zzz","011" 

주, 마지막 두 줄은 (정확하게도) IP 주소 이후에 추가 날짜 문자열을 얻을 :

두 번째와 세 번째 명령을 생산하고 있습니다.

마지막 정규식은 희미한 것이 아닙니다.

IP 주소가 각 구성 요소의 0..255 범위의 숫자와 일치하며 앞에 0이없는 것으로 주장하려는 경우 분명히 정규 표현식의 IP 주소 일치 부분을 강화해야합니다. 그것은 할 수있다; 그것은 예쁘지 않다. 그것은 확장 된 정규 표현식을 수행하는 가장 쉬운 방법입니다 :

([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) 

당신은 이전에 표시된 정규 표현식에 각 [0-9]{3} 단위 대신에이 장치를 사용하십시오.

여전히 큰 따옴표로 묶지 않은 필드는 처리하지 않습니다.

또한 date 명령에서 대체 할 값을 결정하지 않습니다. 즉 (아니라면 초 후) 루틴 쉘 스크립트 신중하게 따옴표 관리에 행할 :

dt=$(date +'%Y-%m-%d %H:%M:%S') 
sed -E 's/^("(([^"]*"")*[^"]*)",){4}"([0-9]{1,3}\.){3}[0-9]{1,3}",/&"'"$dt"'",/' 

'…"'"$dt"'",/' 시퀀스는 단일 인용 문자열로 밖으로 시작 무엇의 일부입니다.첫 번째 큰 따옴표는 문자열의 단순한 데이터입니다. 다음 작은 따옴표가 인용 부호를 끝내고 "$dt"은 쉘 큰 따옴표 안에 date의 값을 삽입합니다 (따라서 공간이 문제가되지 않도록). 작은 따옴표는 작은 따옴표를 다시 시작하고 쉼표 및 쉼표를 추가합니다. 문자열 앞의 슬래시 (sed 인수)가 종료됩니다.

+0

매력처럼 작동 .. 당신은 남자 존입니다. 신뢰 마스터. – Alby

1

시도 : 또한 당신이 원 - 추가 같은 INPUT_FILE

에 동일한 INPUT_FILE 당신이 임시 파일에 명령의 출력 이상 걸릴 이상 (MV 명령) 이름을 바꿀 수를 편집하려면

awk -vdate1=$(date +"%Y-%m-%d") -vdate2=$(date +"%H:%M:%S") -F, '$5 ~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]/{$5=$5 FS date1 " " date2} 1' OFS=, Input_file 

이제는 라이너 형태의 용액이됩니다.

awk -vdate1=$(date +"%Y-%m-%d") -vdate2=$(date +"%H:%M:%S") -F, ' 
      $5 ~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]/{ 
      $5=$5 FS date1 " " date2 
               } 
      1 
    ' OFS=, Input_file 
+3

awk가이 작업을 수행하는 데 좋은 도구가 될 것이라는 데 동의하는 반면, sed를 사용하고 awk가 아닌 요청을 무시합니다. –

관련 문제