awk를 사용하여 공백이 아닌 첫 번째 문자로 텍스트 파일을 레코드로 분할하고 문자열이 포함된 레코드만 인쇄하는 방법

awk를 사용하여 공백이 아닌 첫 번째 문자로 텍스트 파일을 레코드로 분할하고 문자열이 포함된 레코드만 인쇄하는 방법

정보가 덩어리로 구분된 텍스트 파일이 있습니다. 이 청크를 레코드로 분할하여 개별적으로 처리하고 싶습니다.

이것은 내 텍스트 파일(file.txt)입니다.

Alarm Stats:
com.android.calendar
     38ms running, 0 wakeups
     1 alarms: act=com.android.calendar.APPWIDGET_SCHEDULED_UPDATE dat=content://com.android.calendar typ=vnd.
com.android.providers.calendar
     2ms running, 2 wakeups
     2 alarms: act=com.android.providers.calendar.intent.CalendarProvider2 flg=0x14
android
     35563ms running, 11 wakeups
     1 alarms: act=android.intent.action.DATE_CHANGED flg=0x20000014
     1210 alarms: act=android.intent.action.TIME_TICK flg=0x40000014
     120 alarms: act=com.android.server.ThrottleManager.action.POLL flg=0x14
     1 alarms: act=android.net.wifi.DHCP_RENEW flg=0x14
     10 alarms: act=android.content.syncmanager.SYNC_ALARM flg=0x14
com.apollo.apollonetworkcheck
     1026ms running, 88 wakeups
     88 alarms: flg=0x14
com.android.phone
     4ms running, 0 wakeups
     2 alarms: act=com.android.phone.UPDATE_CALLER_INFO_CACHE flg=0x14

검색 문자열로 "apollo"를 사용하면 출력은 다음과 같아야 합니다.

com.apollo.apollonetworkcheck
     1026ms running, 88 wakeups
     88 alarms: flg=0x14

지금까지 내 명령줄에 이 내용이 있지만 검색 문자열 "apollo"를 어디에 넣어야 할지 모르겠습니다. 또한 레코드 구분 기호에 "공백 없음"을 지정하는 방법을 모르겠습니다.

$ awk 'BEGIN { RS = "^RTC" } { print $1 }' file.txt

Archemar, wurtel, steeldriver, terdon, 귀하의 답변은 훌륭하며 문제에 대한 많은 콘텐츠와 리소스 솔루션을 추가합니다. 나는 모든 답변이 가치 있기 때문에 투표했습니다. 물론 "gawk"가 포함된 명령은 unix/linux 명령 사용의 문제점과 목표를 더 정확하게 표현합니다.

답변1

나는 항상 모든 것에 Perl을 넣었습니다 :-)

perl -ne 'if (/^\s/) { $x.=$_ }else{print $x if $x=~/apollo/; $x=$_} END {print $x if $x=~/apollo/}' file.txt

편집: 한 줄에 대한 설명:

  • -n은 기본적으로 각 루프의 끝에서 인쇄하지 않고 입력을 반복한다는 의미입니다(-p는 동일하지만 기본적으로 행을 인쇄합니다).
  • -e는 표현식 또는 코드 조각을 지정합니다. 이는 암시적 루프 내에서 수행됩니다.
  • 완전한 "레코드"가 발견될 때까지 $x 변수를 사용하여 입력 텍스트를 버퍼링합니다.
  • /^\s/는 줄 시작 부분의 공백과 일치합니다. 발견되면 입력 라인이 $x 버퍼에 추가됩니다. 그렇지 않은 경우 "logging"이 완료되고 검색 문자열 "apollo"가 확인됩니다. 발견되면 기록을 인쇄하십시오. 버퍼는 처리 후에 지워집니다.
  • END {} 부분은 루프가 완료된 후 실행되어 입력의 마지막 레코드의 경우를 처리합니다.

답변2

구분 기호를 기록하기 위해 정규식을 사용한다는 아이디어는 우아하지만 awk는 해당 텍스트를 소비할 것이라는 점을 명심하십시오. 귀하의 경우 해당 텍스트의 공백이 아닌 첫 번째 문자가 됩니다.다음과 같은기록.

시스템에 awk의 GNU 버전이 있는 경우 변수를 통해 가장 최근에 일치하는 RS에 액세스할 수 있지만 RT다음 레코드의 시작 부분으로 다시 연결할 수 있도록 결과를 저장해야 합니다. 아마도 다음과 같습니다.

gawk 'BEGIN{RS="\n[^[:blank:]]"}; {lastRT=RT}; /apollo/ {$0=substr(lastRT,2)""$0; print}' file.txt

substr(lastRT,2)공백이 아닌 문자만 앞에 추가되도록 일치 항목에서 개행 문자를 제거합니다 .

답변3

awk와 매개변수 사용

(파일 filter.awk)

BEGIN { p=0 ; } # no printing
 { if ( (substr($0,1,1) != " ") && (substr($0,1,1) != "\t" ) ) p=0 ; # if no blank stop printing
   if ( index($0,name) > 1 ) p=1 ; # pattern found ?
  if (p) print ;
 }
  • $0은 전체 줄입니다.
  • substr($0,1,1)은 줄의 첫 번째 문자입니다.

및 결과

awk -v name=apollo -f filter.awk a.txt

    com.apollo.apollonetworkcheck
     1026ms running, 88 wakeups
     88 alarms: flg=0x14

답변4

나는 또한 모든 것에 Perl을 적용했지만 때로는 sed약간의 양념을 추가했습니다.

$ sed  's/^\w/\n&/' file | perl -000ne 'print if /apollo/'
com.apollo.apollonetworkcheck
    1026ms running, 88 wakeups
    88 alarms: flg=0x14

이렇게 하면 sed각 레코드 사이에 추가 줄바꿈이 추가됩니다. 영숫자 문자( ^\w)로 시작하고 해당 문자를 개행 문자로 바꾼 다음 문자 자체( \n&, &"방금 일치한 내용"을 의미)가 오는 줄을 찾습니다 . 결과는 단락처럼 보이는 레코드가 있고 그 앞에 빈 줄이 있는 파일입니다.

이제 에 의해 활성화된 Perl의 "단락 모드"를 사용할 수 있습니다 -000. (입력 레코드를 레코드별로 읽기) 과 결합하면 -n전체 레코드를 한 번에 읽을 수 있습니다. 따라서 우리가 해야 할 일은 원하는 패턴과 일치하는 경우 현재 "라인"(레코드)을 인쇄하는 것뿐입니다. 이 경우에는 apollo.

이 기호가 얼마나 이식성이 있는지 잘 모르겠습니다 \w. sed처리할 수 없는 경우 다음을 사용하세요.

sed  's/^[^ \t]/\n&/' file | perl -000ne 'print if /apollo/'

동일한 방법을 사용할 수도 있습니다 awk.

$ sed  's/^[^ \t]/\n&/' file | awk -v RS="\n\n" '/apollo/'
com.apollo.apollonetworkcheck
     1026ms running, 88 wakeups
     88 alarms: flg=0x14

관련 정보