두 패턴(0과 1) 사이의 최대값 $4를 찾아 변수에 설정합니다.

두 패턴(0과 1) 사이의 최대값 $4를 찾아 변수에 설정합니다.

.txt를 필터링하기 위해 .awk 소스 파일을 작성하려고 하는데 두 번째 명령에서 max 변수를 사용하는 방법을 알고 싶습니다.

BEGIN {max1=0} 

두 패턴(0과 1) 사이의 최대값 $4를 찾아 변수에 설정합니다.

{if ($4>0 && $4<1)
max1=$4
else if ($4==1)
max=max1}
END {print max}

/Nodes/ {f=1} /EndNodes/ {f=0} #Gives lines after Nodes and before EndNodes
{if ($2+0>=0 && $3+0==0 && max==$4)  #Filters the given lines between Nodes and EndNodes
{print $1}}

내 생각엔 max 변수를 정의한 후 처음부터 프로그램을 실행해야 할 것 같습니다. (두 번째 명령과 동일한 라인을 사용하기 때문입니다.)

예상 출력은 다음과 같습니다: 20, 31 및 32

입력하다

$Nodes
  34
   1  0.0000000E+000  0.0000000E+000  0.0000000E+000
   2  6.0000000E-003  0.0000000E+000  0.0000000E+000
   3  0.0000000E+000  6.0000000E-003  0.0000000E+000
   4 -6.0000000E-003  0.0000000E+000  0.0000000E+000
   5  0.0000000E+000 -6.0000000E-003  0.0000000E+000
   6  2.1213203E-003  2.1213203E-003  0.0000000E+000
   7 -2.1213203E-003  2.1213203E-003  0.0000000E+000
   8 -2.1213203E-003 -2.1213203E-003  0.0000000E+000
   9  2.1213203E-003 -2.1213203E-003  0.0000000E+000
  10  4.2426407E-003  4.2426407E-003  0.0000000E+000
  11 -4.2426407E-003  4.2426407E-003  0.0000000E+000
  12 -4.2426407E-003 -4.2426407E-003  0.0000000E+000
  13  4.2426407E-003 -4.2426407E-003  0.0000000E+000
  14  2.1213203E-003  0.0000000E+000  0.0000000E+000
  15  0.0000000E+000  2.1213203E-003  0.0000000E+000
  16 -2.1213203E-003  0.0000000E+000  0.0000000E+000
  17  0.0000000E+000 -2.1213203E-003  0.0000000E+000
  18  0.0000000E+000  2.1213203E-003  6.0000000E-003
  19  0.0000000E+000  6.0000000E-003  6.0000000E-003
  20  0.0000000E+000  0.0000000E+000  6.0000000E-003
  21 -4.2426407E-003  4.2426407E-003  6.0000000E-003
  22 -2.1213203E-003  2.1213203E-003  6.0000000E-003
  23 -6.0000000E-003  0.0000000E+000  6.0000000E-003
  24 -2.1213203E-003  0.0000000E+000  6.0000000E-003
  25 -4.2426407E-003 -4.2426407E-003  6.0000000E-003
  26 -2.1213203E-003 -2.1213203E-003  6.0000000E-003
  27  0.0000000E+000 -6.0000000E-003  6.0000000E-003
  28  0.0000000E+000 -2.1213203E-003  6.0000000E-003
  29  4.2426407E-003 -4.2426407E-003  6.0000000E-003
  30  2.1213203E-003 -2.1213203E-003  6.0000000E-003
  31  6.0000000E-003  0.0000000E+000  6.0000000E-003
  32  2.1213203E-003  0.0000000E+000  6.0000000E-003
  33  4.2426407E-003  4.2426407E-003  6.0000000E-003
  34  2.1213203E-003  2.1213203E-003  6.0000000E-003
$EndNodes
$Elements
#And some more data
$EndElements

답변1

일회성 솔루션은 다음과 같습니다.

/Nodes/         { read = 1 }
/EndNodes/      { read = 0 }

!read           { next     }

NF == 4                         { n = $1; x = $2; y = $3; z = $4 }
z > max                         { delete set; i = 1; max = z     }
x >= 0 && y == 0 && z == max    { set[i++] = n                   }

END             { for (i in set) { print set[i] } }

read변수는 현재 레코드에 대해 작업을 수행해야 하는지 여부를 결정합니다. 1이면 이렇게 합니다.

현재 입력에 관심이 없으면 세 번째 블록은 현재 입력을 버리고 위에서부터 다음 레코드를 계속 처리합니다.

블록 4는 4개의 편의 변수 , nx를 설정합니다 y. 다른 것보다 z읽기가 더 쉽습니다 .$1

블록 5에서는 배열을 삭제합니다 set. 이 set배열은 조건을 충족하는 지금까지 찾은 모든 노드 번호의 모음입니다. 새로운 최대값을 찾으면 이 블록이 실행되므로 z이전에 발견된 모든 노드는 무효화됩니다. 또한 새로운 최대값( max)을 저장합니다. 변수는 i단지 배열의 인덱스입니다(기본적으로 카운터). 최대값을 찾지 못한 경우 max초기화되지 않은 값은 테스트에서 0으로 처리됩니다.

조건을 만족하는 노드를 찾으면 6번째 블록이 실행됩니다. 노드 번호는 set배열에 저장되고 i증가됩니다.

set마지막으로 배열을 반복 하고 해당 내용을 인쇄합니다.

GNU에서 실행한 결과는 awk다음과 같습니다.

20
31
32

BSD awkmawkOpenBSD에서 실행하면 목록이 역순으로 생성됩니다.

답변2

해결책:

get_max_nodes.awk스크립트:

#!/bin/awk -f
BEGIN{ max=0 }
NR==FNR{                         # processing the 1st input file
    if ($4~/^[0-9]/) {           # if the 4th field is a number
        if($4+0 > max) max=$4+0  # capturing maximal number
    }
    next
}
{   # processing the 2nd input file (same file)
    if ($4~/^[0-9]/ && $2+0>=0 && $3+0==0 && $4+0==max) {
        print $1
    }
}

용법:

awk -f get_max_nodes.awk input.txt input.txt

산출:

20
31
32

답변3

댓글을 달기에는 평판이 부족해서 답변을 하게 되었습니다. 내 첫 번째 의견은 awk가 실수 수학을 수행하는 데 가장 적합한 도구가 아니라는 것입니다. 문자열과 정수가 더 좋습니다.

awk에 대한 다른 사항: BEGIN 단락은 입력에서 줄을 읽기 전에 발생합니다. END 단락은 모든 줄을 읽은 후에 발생합니다.

참고: awk는 코드에 레코드/필드를 저장하는 단계를 수행하지 않는 한 현재 입력 라인/레코드 이외의 어떤 것도 저장하거나 신경 쓰지 않습니다. 이는 BEGIN과 END 사이에 발생해야 합니다.

이 단락 사이의 코드는 변수를 설정/재설정만 하고 해당 값에는 아무 작업도 수행하지 않습니다. 기본적으로 입력 파일을 -1로 마무리하고 출력을 파이프하여 비슷한 결과를 얻을 수 있습니다.

귀하의 의도는 최대 또는 최대 1을 찾기 위해 열 4의 숫자를 테스트하고, 열 4에 이 최대값이 포함되어 있으면 열 1만 인쇄한 다음 열 2와 3을 성공적으로 테스트하는 것입니다. 파일의 마지막 줄에만 관심이 있는 경우가 아니면 이 논리를 END 앞으로 이동해야 합니다.

awk에서는 각 입력 줄이 (기본적으로) 각 조건과 비교된다는 점을 기억하세요. 조건이 true이면 작업 또는 작업 목록을 실행합니다. 동일한 행에 작업을 트리거하는 여러 조건이 있을 수 있습니다.

첫인상은 프로세스를 재평가해야 한다는 것입니다. 중요도를 결정하고 그에 따라 행동하십시오. 예를 들어, 나에게 첫 번째 중요한 순서는 입력 파일의 두 플래그 사이의 데이터에서만 작동합니다. 다음으로, 4개 필드 각각의 실수가 의미를 잃지 않고 정수(또는 문자열)로 변환(또는 처리)될 수 있는지 여부를 결정합니다. 실제 데이터 자체는 변경할 필요가 없으며 코드에서의 표현만 변경할 수 있습니다. 이를 다시 변환할 수 있지만 원래 숫자의 정확성을 잃을 가능성이 높습니다. 마지막으로 나중에 처리하기 위해 정렬되지 않은 임의의 데이터 전체/모든 데이터를 저장할지 아니면 각 출력 행을 즉시 제공할지 선택합니다.

다음 메타 예제는 더 효율적으로 수행될 수 있습니다. 구문 분석을 시작할 시간인지 알려주는 플래그로 시작합니다. $0 ~= /Nodes/를 본 적이 있나요? 시작=0. $0 ~= /EndNodes/ line, stop=0을 테스트하여 데이터 구문 분석을 중지할 시기를 알 수 있도록 준비할 수도 있습니다. 데이터를 저장하려면 아마도 count=0이라는 카운터가 필요할 것입니다.

BEGIN {
   start=0
   stop=0
   count=0
   max=0
}
/EndNodes/ {
   stop=1
}
/Nodes/ {
   start=1
}
NF==4 {
   if (start==1 && stop==0) {
      count++
      column1[count]=$1
      column2[count]=substr($2,1,index($2,".")-1)
      column3[count]=substr($3,1,index($3,".")-1)
      column4[count]=substr($4,1,index($4,".")-1)
   }
}
# Now print column1 if column2 is non-negative and column3=0 and column4=max
# In the first loop through the array/list, find max
END {
   for (loop=1;loop<=count;loop++) {
      if (column4[loop]>max) {
         max=column4[loop]
      }
   }
   for (loop=1;loop<=count;loop++) {
      if (column4[loop]==max && column3[loop]==0 && column2[loop]>=0) {
         print column1[loop]
      }
   }
}

작성된 대로 출력은 다음과 같습니다.

20
31
32

관련 정보