awk는 sed의 파이프 출력을 처리할 수 없습니다.

awk는 sed의 파이프 출력을 처리할 수 없습니다.

대략 다음과 같은 로그 파일이 있습니다.

Sep 23 10:28:26 node kernel: em0: device is going DOWN
Sep 23 10:28:26 node kernel: em0: device is going UP
Sep 23 10:29:14 node cdsmon: /tmp/instance0 ; core dumped
Sep 23 10:29:14 node cdsmon: /tmp/instance0 ; core dumped
Sep 23 10:28:26 node kernel: em0: device is going DOWN
Sep 23 10:29:14 node cdsmon: /tmp/instance1 ; core dumped
Sep 23 10:28:26 node kernel: em0: device is going UP
Sep 23 10:29:14 node cdsmon: /tmp/instance2 ; core dumped

cdsmon행을 감지한 다음 행을 분할 하고 싶습니다 ( 유사한 이벤트를 ;가져오기 위해 )./tmp/instance0core dumped

이를 위해 다음을 사용합니다 sed.

sed -u -n -e "s/^.*cdsmon: //p" /tmp/dev.log

출력은 다음과 같습니다.

/tmp/instance0 ; core dumped
/tmp/instance0 ; core dumped
/tmp/instance1 ; core dumped
/tmp/instance2 ; core dumped

그러나 이 출력을 awk아래와 같이 파이핑하면 위와 동일한 출력이 제공됩니다.

sed -u -n -e "s/^.*cdsmon: //p" /tmp/dev.log | awk -F ";" "{print $1}"

-u옵션을 제거했음에도 불구하고 동일한 상황이 관찰되었습니다 sed.

내가 뭔가를 놓치고 있다면 누군가가 그것을 지적해 줄 수 있나요? 저는 일반 awk/sed와 함께 FreeBSD 상자를 사용하고 있는데 불행하게도 새 패키지를 설치할 수 없습니다.

답변1

이 동작의 이유는 awk프로그램을 다음에 포함시켰기 때문입니다.더블따옴표는 문자열을 쉘의 변수 확장에 공개하도록 만듭니다. 이는 프로그램을 실행하는 셸이 먼저 확장되고 $1이것이 정의되지 않을 수 있으므로 빈 문자열로 확장된다는 의미입니다.

따라서 귀하의 프로그램은 다음과 같습니다.

awk -F ";" "{print}"

이것이 전체 라인이 인쇄되는 이유입니다. 이것이 항상 awk(및 ) 프로그램을sed하나의인용 부호.

sed대부분의 경우 출력을 파이프 로 연결하거나 awk그 반대로 파이프할 필요가 없습니다 . 귀하의 예에서 "이벤트 태그" 다음의 첫 번째 필드를 가져오려면 다음을 수행할 수 있습니다.

sed -E -n 's/^.*cdsmon: ([^;]*).*$/\1/p' /tmp/dev.log 

이는 다음을 정의합니다.캡처 그룹cdsmon:첫 번째 문자열 다음에 문자열을 둘러싸고 ;전체 줄을 해당 캡처 그룹의 내용으로 바꿉니다.

기록된 이벤트의 요약을 인쇄하려면 위 방법을 다음과 같이 확장 cdsmon할 수 있습니다 .sed

sed -E -n 's/^.*cdsmon: ([^;]*) ; (.*)$/\1 : \2/p' dev.log 

또는 또 다른 awk유일한 접근 방식이 있습니다.

awk -F'(cdsmon: | ; )' 'NF==3{printf "%s : %s\n",$2,$3}' dev.log 

귀하의 예를 들어, 둘 다 인쇄됩니다

/tmp/instance0 : core dumped
/tmp/instance0 : core dumped
/tmp/instance1 : core dumped
/tmp/instance2 : core dumped

그러나 이 awk방법에서는 극단적인 경우가 발생할 수 있습니다. 패턴 cdsmon:;필드 구분 기호를 사용합니다 . 세 개의 필드가 있는 경우(예에서는 항목에서만 발생할 수 있음 cdsmon:) after 인스턴스 이름 cdsmon:과 after 이유 에 해당하는 두 번째 및 세 번째 필드를 인쇄합니다 ;.

답변2

awk수술 내내 사용 하겠습니다 . 여기서는 콜론으로 분할하므로 14 node cdsmon날짜/시간을 고려한 후 호스트 일치를 세 번째 필드(예:)에 적용해야 합니다.

awk -F: '
    $3 ~ / cdsmon$/ {
        split($4, text, / *; */);    # Split field at semicolon
        sub(/^ */, "", text[1]);     # Remove leading space
        printf "instance %s, reason %s\n", text[1], text[2]
    }
' /tmp/dev.log

이는 다음에서 제안된 대안적이고 간단한 솔루션입니다.논평, 콜론이나 세미콜론으로 분할하므로 필요한 필드가 이미 awk변수에 직접 있습니다.

awk -F': | *; *' '
    $1 ~ / cdsmon$/ { printf "instance %s, reason %s\n", $2, $3 }
' /tmp/dev.log

인스턴스를 추출하려는 방법과 이유를 설명하지 않았으므로(혹은 그랬다면 놓쳤습니다), 그냥 문자열로 인쇄하여 올바르게 추출되었음을 증명했습니다.

답변3

지시에 따르면:

큰따옴표는 개시 가격과 마감 가격 사이의 대부분의 모든 것을 보호합니다. 쉘은 인용된 텍스트에 대해 최소한 변수 및 명령 대체를 수행합니다. 다른 쉘은 큰따옴표로 묶인 텍스트에 대해 다른 유형의 처리를 수행할 수 있습니다.

큰따옴표로 묶인 텍스트의 일부 문자는 셸에서 처리되므로 텍스트 내에서 이스케이프 처리해야 합니다. 주목할 만한 문자는 '$', '``', '\' 및 '"'이며 문자 그대로 프로그램에 전달하려면 큰따옴표로 묶인 텍스트에서 이들 모두 앞에 백슬래시가 와야 합니다.

따라서 귀하의 경우에는 달러 기호를 피할 수 있습니다 $.

sed -u -n -e "s/^.*cdsmon: //p" /tmp/dev.log | awk -F ";" "{print \$1}"

그러나 작은따옴표를 사용하는 것이 더 쉽습니다.

sed -u -n -e "s/^.*cdsmon: //p" /tmp/dev.log | awk -F ' ; ' '{ print $1 }'

' ; '각 줄 뒤에 보이지 않는 공백이 없도록 구분 기호 사이에 공백을 둘 수도 있습니다 .

다음을 사용할 수도 있습니다 awk.

$ awk -F': | ; ' '/cdsmon/ { print $2 }' /tmp/dev.log
/tmp/instance0
/tmp/instance0
/tmp/instance1
/tmp/instance2

답변4

awk '{for(i=1;i<=NF;i++){if($i ~ /cdsmon/){print $(i+1),$(i+3),$(i+4)}}}' filename

산출

/tmp/instance0 core dumped
/tmp/instance0 core dumped
/tmp/instance1 core dumped
/tmp/instance2 core dumped





awk '{for(i=1;i<=NF;i++){if($i ~ /cdsmon/){print $(i+1)}}}' filename
/tmp/instance0
/tmp/instance0
/tmp/instance1
/tmp/instance2

관련 정보