.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개의 편의 변수 , n
및 x
를 설정합니다 y
. 다른 것보다 z
읽기가 더 쉽습니다 .$1
블록 5에서는 배열을 삭제합니다 set
. 이 set
배열은 조건을 충족하는 지금까지 찾은 모든 노드 번호의 모음입니다. 새로운 최대값을 찾으면 이 블록이 실행되므로 z
이전에 발견된 모든 노드는 무효화됩니다. 또한 새로운 최대값( max
)을 저장합니다. 변수는 i
단지 배열의 인덱스입니다(기본적으로 카운터). 최대값을 찾지 못한 경우 max
초기화되지 않은 값은 테스트에서 0으로 처리됩니다.
조건을 만족하는 노드를 찾으면 6번째 블록이 실행됩니다. 노드 번호는 set
배열에 저장되고 i
증가됩니다.
set
마지막으로 배열을 반복 하고 해당 내용을 인쇄합니다.
GNU에서 실행한 결과는 awk
다음과 같습니다.
20
31
32
BSD awk
및 mawk
OpenBSD에서 실행하면 목록이 역순으로 생성됩니다.
답변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