파일에서 일련의 줄을 삭제하는 방법은 무엇입니까?

파일에서 일련의 줄을 삭제하는 방법은 무엇입니까?

로그 파일을 구문 분석하고 중요한 메시지가 발견되면 이메일을 보내는 ksh 스크립트를 작성 중입니다. 일부 메시지는 정보 제공용이므로 무시하고 싶습니다.

로그 파일의 형식은 다음과 같습니다.

2018-01-24.08.24.35.875675    some text

    more text
    more text
    more text
    more text

2018-01-24.08.24.37.164538    some text

    more text
    more text
    INF9999W        <-- informational text
    more text

2018-01-24.08.24.46.8602545    some text

    more text
    more text
    more text

타임스탬프는 메시지 구분 기호로 처리되며 타임스탬프는 그 뒤의 메시지에 속합니다. "메시지 텍스트"가 나타날 때마다 파일을 검색한 다음 파일에서 전체 메시지를 삭제하고 싶습니다(이전 타임스탬프부터 다음 타임스탬프 직전까지).

다음을 사용하여 해당 줄을 삭제할 수 있도록 이전 및 다음 타임스탬프의 줄 번호를 쉽게 확인하려면 어떻게 해야 합니까?

awk 'NR<'$preceding_ts' || NR >='$following_ts'

내 접근 방식은 모든 타임스탬프 줄을 파일에 넣은 다음 "정보 텍스트" 줄 # 앞뒤의 타임스탬프 줄을 찾을 때까지 파일을 반복하는 것이었습니다. 특히 대용량 파일을 작업할 때 작업량이 많은 것 같습니다. 더 효율적인 방법이 있습니까?

integer inf_line
integer last_ts_line
integer cur_ts
cp $error_log $copy_log
while true
do
   inf_line=$(grep -n "INF99999W" $copy_log | head -1 | cut -f1 -d":")
   if [[ $inf_line -eq 0 ]]
   then
      break
   fi     
   grep -n -E "^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]-" $copy_log | cut -f1 -d":" > $ts_lines
   last_ts_line=99999999
   cat $ts_lines | while read cur_ts
   do       
      if [[ $cur_ts -gt $inf_line && $last_ts_line -lt $inf_line ]]
      then
         awk 'NR<'$last_ts_line' || NR >='$cur_ts'' $copy_log > $temp_log
         cp $temp_log $copy_log
         last_ts_line=$cur_ts
         break
      fi
      last_ts_line=$cur_ts
   done
   if [[ $last_ts_line -lt $inf_line ]]
   then
      awk 'NR<'$last_ts_line'' $copy_log > $temp_log
      cp $temp_log $copy_log
   fi
done

감사해요.

답변1

현재 메시지의 행을 저장하여 구현하고 메시지가 끝날 때 INF표시가 없으면 저장된 배치를 인쇄합니다. 여기서 d현재 메시지(d는 데이터를 나타냄)를 보유하는 행은 p저장된 행을 인쇄할지 여부를 알려줍니다.

awk -vinfo='INF99+' \
    '/^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]/ {
         if (p) printf "%s", d; d = $0 ORS; p=1; next } 
     $0 ~ info {p=0} 
     {d = d $0 ORS} 
     END {if (p) printf "%s", d}' < log 

여기의 첫 번째 규칙은 타임스탬프 행과 일치하고 true인 경우 저장된 행을 인쇄하고 해당 행을 저장한 후 1로 p설정합니다 . 두 번째 규칙은 p해당 패턴이 있는 줄이 보이면 0으로 재설정됩니다. 패턴이 변수로 설정됩니다 . 세 번째 규칙은 현재 행을 수집된 행에 추가하고, 다시 이 규칙은 설정된 경우 수집된 행만 인쇄합니다 .pinfo-vinfo=...ENDp


info타임스탬프 행의 패턴을 확인하는 다음과 같이 작성할 수도 있습니다 .

awk -vinfo='INF99+' \
    '/^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]/ {
         if (p) { printf "%s", d }; d = ""; p=1; } 
     $0 ~ info {p=0} 
     {d = d $0 ORS} 
     END {if (p) printf "%s", d}' < log 

일반적으로 awkPerl이나 Perl에서 이와 같은 내용을 작성하는 것은 아마도 좋은 생각일 것입니다. 결과는 적어도 수십 개의 fork grep, awk등 의 복사본이 있는 쉘 스크립트보다 훨씬 빠릅니다.cut

관련 정보