다음 줄이 누락된 경우 해당 줄을 인쇄하세요.

다음 줄이 누락된 경우 해당 줄을 인쇄하세요.

이는 다음과 관련이 있습니다.일치하는 항목이 있으면 awk는 2줄을 인쇄합니다.그러나 내 명령에는 해결할 수 없는 버퍼링 문제가 있으므로 stderr를 완전히 무시하고 특정 줄이 누락된 출력을 찾는 것이 더 나은 접근 방식이라고 생각합니다.

그래서 내 출력은 다음과 같습니다

Gathering drive descriptors ...
Gathering data for drive 0 ...
Drive Model: DataTraveler 2.0
Gathering data for drive 1 ...
Drive name:  id1,sd@n5000cca17096
Drive Model: HUH721010AL4204
Drive Speed: 7200 RPMs
Drive Temp:  41 C

Gathering data for drive 2 ...
Drive name:  id1,sd@n5000cca24156
Drive Model: HUH721010AL4204
Drive Speed: 7200 RPMs
Drive Temp:  41 C

Gathering data for drive 3 ...
Drive name:  id1,sd@n5000cca8749
Drive Model: HUH721010AL4204
Gathering data for drive 4 ...
Drive name:  id1,sd@n5000cca19183
Drive Model: HUH721010AL4204
Drive Speed: 7200 RPMs
Drive Temp:  41 C

Gathering data for drive 5 ...
Drive name:  id1,sd@n5000cca4607
Drive Model: HUSMH8010BSS204
Gathering data for drive 6 ...
Drive name:  id1,sd@n5000cca10152
Drive Model: HUH721010AL4204
Drive Speed: 7200 RPMs
Drive Temp:  41 C

Drive name누락된 행에 대한 Drive Speed드라이버 Drive Temp를 출력하고 싶습니다 .

출력은 다음과 같아야 합니다.

Drive name:  id1,sd@n5000cca8749
Drive name:  id1,sd@n5000cca4607

이것은 내 능력 밖의 일이지만 할 수 있다고 확신 awk하지만 사용할 계획은 없으며 awk작업을 완료하는 모든 것이 가능합니다(GNU 도구 없음). 감사해요!

답변1

mawk및 다음을 사용하여 gawk정규식 및 다중 문자 RS(레코드 구분 기호) 를 지원합니다.

awk -v RS='Gathering data' -F'\n' '/Drive name/ && !/Drive Speed/ && !/Drive Temp/{print$(NF-2)}' file

이를 지원하지 않는 경우 awk입력을 필터링하여 폼 피드와 같은 단일 문자로 바꿀 수 있습니다.

awk '/Gathering data/{$0="\f"} 1' file | awk -v RS='\f' -F'\n' '/Drive name/ && !/Drive Speed/ && !/Drive Temp/{print$(NF-2)}'

레코드의 행이 고정된 순서가 아닌 경우 이를 생략하여 전체 레코드를 인쇄한 {print ...}다음 grep 등을 사용하여 출력을 필터링할 수 있습니다.

이 접근 방식의 장점은 일치 조건을 명확한 방법(예: /Drive Speed: 7200 RPMs/대신 등 !/foo/ && !/bar/)으로 수정할 수 있고, 전체 파일을 메모리에 로드하지 않으며, 가장 중요한 것은 수동 상태를 작성할 필요가 없다는 것입니다. 기계.

답변2

다음은 Perl 버전입니다.

#!/usr/bin/env bash

perl -ne '
    $l = $_ if (/Drive name:/);
    $s = 1  if (/Drive Speed:/);
    if (/^\s*$/) {
        print "$l\n" if (! defined($s));
        $s = undef;
    }
' "$1"

입력 파일 끝에 빈 줄이 있다고 가정합니다.

실행: test.sh 파일

답변3

RS필드 순서에 의존할 수 있다면 여러 문자가 필요하지 않습니다.

awk '/Drive name/ {if (!LCNT && OLDNM) print OLDNM; OLDNM = $3; LCNT = 0} /Drive (Speed|Temp)/ {LCNT++}' file3
id1,sd@n5000cca8749
id1,sd@n5000cca4607

답변4

데이터에 레이블/이름 및 값 쌍이 있을 때마다 코드에서 모방하는 배열을 생성/사용하는 것이 가장 좋습니다. 여러 줄의 레코드 블록이 있는 경우에도 마찬가지입니다. 이전 질문에서 나는 기록이 빈 줄로 구분될 때 무엇을 해야 하는지 보여주었습니다(참조:https://unix.stackexchange.com/a/562552/133219), 존재하지 않는 경우 이를 수행하는 방법과 레코드의 각 값 위치에 의존하는 대신 보다 일반적인 tag-val 접근 방식을 사용하는 방법은 다음과 같습니다.

$ cat tst.awk
BEGIN { FS=": *" }
/^Gathering data/ { prt() }
{ tags2vals[$1] = $0 }
END { prt() }

function prt() {
    if ( ("Drive name" in tags2vals) && ( !("Drive Speed" in tags2vals) || !("Drive Temp" in tags2vals) ) ) {
        print tags2vals["Drive name"]
    }
    delete tags2vals
}

$ awk -f tst.awk file
Drive name:  id1,sd@n5000cca8749
Drive name:  id1,sd@n5000cca4607

관련 정보