대략 다음과 같은 로그 파일이 있습니다.
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/instance0
core 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