파일에 있는 각 항목의 최대값과 최소값을 찾아야 합니다.
#subset of my file
NEUTRON 20.900103
PION- 0.215176
PION- 22.716532
NEUTRON 8.043279
PION+ 1.374297
PION- 0.313350
PION+ 0.167848
항목 이름이 여러 개인 경우 파일을 반복하여 각 이름의 최소값과 최대값을 찾는 방법은 무엇입니까? 나는 awk를 사용하여 각 항목의 수를 세었고 중복된 항목은 없지만 각 이름의 각 반복에는 숫자가 포함되어 있으며 그 숫자는 각 항목의 최대값과 최소값에 대해 필터링하려고 하는 것입니다. ex 전체 파일의 출력:
Name Count Minimum Maximum
-------- ----- --------- ---------
KAON- 1 5.489958 5.489958
NEUTRON 2 8.043279 20.900103
PHOTON 10 0.034664 1.897264
PION- 5 0.192247 22.716532
PION+ 7 0.167848 7.631051
PROTON 1 1.160216 1.160216
답변1
awk '{
count[$1]++
min[$1]=(!($1 in min) || $2<min[$1]) ? $2 : min[$1]
max[$1]=(!($1 in max) || $2>max[$1]) ? $2 : max[$1]
}
END {
print "Name","Count","Minimum","Maximum"
print "----","-----","-------","-------"
for(i in count) print i,count[i],min[i],max[i]
}' file | column -t
최소 배열 값 할당의 논리는 다음과 같습니다.
첫 번째 필드의 이름이 배열에 존재하지 않는 경우( !($1 in min)
) 또는 ( ||
) 두 번째 필드가 현재 배열 값( $2<min[$1]
)보다 작은 경우 ( ?
)는 새 값을 할당하고 $2
else( :
)는 이전 값을 지정합니다 min[$1]
.
| column -t
결과를 표로 예쁘게 인쇄하는 데 사용됩니다 . 필요없으시면 삭제하셔도 됩니다.
산출:
Name Count Minimum Maximum
---- ----- ------- -------
PION+ 2 0.167848 1.374297
PION- 3 0.215176 22.716532
NEUTRON 2 8.043279 20.900103
답변2
Jeff Schaller가 지적했듯이 bash는 텍스트 프로세서는 아니지만 요청한 내용은 구현하기가 특별히 어렵지 않습니다. 그래서 여기에 그 일을 할 수 있는 방법이 있습니다. 그만한 가치가 있는 일이죠.
$ awk '!/^#.*/ {
((++cnt[$1]));
if (cnt[$1]==1)
{min[$1]=max[$1]=$2}
else if ($2 < min[$1])
{ min[$1]=$2}
else if ($2 > max[$1])
{max[$1]=$2}
}
END {
printf "%-10s%7s%10s%12s\n","Name","Count","Minimum", "Maximum";
for (i in cnt)
printf "%-10s%7d%10.6g%12.8g\n", i,cnt[i],min[i],max[i];
}' testdata
산출:
Name Count Minimum Maximum
PION+ 2 0.167848 1.374297
PION- 3 0.215176 22.716532
NEUTRON 2 8.04328 20.900103
설명하다:
- 다음으로 시작하는 줄(레코드)을 건너뜁니다.
#
awk
각 레코드에 대해 cnt[$1]은 프로그램 실행 시작 시 0부터 시작하여 1씩 증가됩니다.- 현재 레코드의 첫 번째 필드 값 "$1"이 이전에 본 적이 없는 경우 해당 값의 최소값과 최대값을 "$2" 값으로 초기화합니다.
- 다른 경우(이전 레코드에서 "$1" 값이 한 번 이상 표시되는 경우) 최소값과 최대값을 업데이트합니다.
- 마지막으로 OP의 예제 출력 측면을 존중하기 위해 형식화된 인쇄를 사용합니다.