2017-10-25 1 views
2

'$ value1 value2'형식의 "헤더 행"이있는 각 블록에 대해 $ 3 열의 가장 작은 값을 찾고 싶습니다. 이 파일은 다음과 같이 보입니다awk를 사용하여 각 블록의 열에서 최소값을 찾습니다.

@ 62.65 -50.35 
0 1.50 1.676 
1.67 1.50 1.677 
1.67 2.25 1.423 
2.90 2.25 2.902 
2.90 4.95 2.903 
3.04 4.95 3.049 
@ 63.61 -50.45 
0 1.50 1.654 
3.42 1.50 1.875 
3.43 2.19 3.430 
5.31 2.19 1.032 
5.32 6.23 5.320 
5.43 6.23 5.434 

이 후, 가장 작은 $ 3을 사용하여 전체 줄뿐만 아니라 전체 줄을 인쇄하려고합니다. (I 시도

awk '{if (!/^@/) {if ($3 < min) {$3=min;} print $1, $2, $3, min; min = $3;} else if (/^@/) min = 10; print $1 $2 $3;}' input.txt > output.txt 

나는 블록을 분리하고 분 "재설정"하는 문제가 있습니다

그래서, 내 출력 파일이 내가 지금까지 뭘하려

@ 62.65 -50.35 
1.67 2.25 1.423 
@ 63.61 -50.45 
5.31 2.19 1.032 

과 같아야합니다 '시작'값을 높게 설정 - 예 : 10).

나는 프로그래밍에 익숙하며 지금까지 awk를 주로 사용했다 - 나를 도울 수 있다면 정말 좋을 것이다! 정말 고마워! 건배, 있겠지

+2

에 저장되어있는 선을 인쇄해야합니다 예상 출력은 무엇인가, 당신이 질문을 편집 할 수 있고, 나보다 더 적은이다 그것을 제공하십시오. – anubhava

+1

또한 지금까지 시도를 추가하십시오. 작동하지 않으면 괜찮습니다. – ghoti

+0

안녕하세요. 너는 무엇을 이미 시도 했는가? 주저하지 말고 [도움말 센터] (https://stackoverflow.com/help)를 방문하십시오. –

답변

3

사용 AWK :

awk '/^@/{if(h){print h RS m}min=""; h=$0; next}min=="" || $3 < min{min=$3; m=$0}END{print h RS m}' infile 

array

awk '/^@/{h=$0;min="";next}min==""||$3<min{min=$3;l[h]=$0}END{for(i in l)print i RS l[i]}' infile 

더 나은 읽을 수있는 사용 :

awk '/^@/{ 
      if(h){ 
       print h RS m 
      } 
      min=""; h=$0; next 
     } 
    min=="" || $3 < min{ 
      min=$3; 
      m=$0 
    } 
    END{ 
      print h RS m 
    } 
    ' infile 

array

awk '/^@/{ 
      h=$0;min=""; 
      next 
    } 
    min==""||$3<min{ 
      min=$3; 
      l[h]=$0 
    } 
    END{ 
      for(i in l) 
       print i RS l[i] 
    } 
    ' infile 
0123을 사용하여

테스트 결과 :

$ cat infile 
@ 62.65 -50.35 
0 1.50 1.676 
1.67 1.50 1.677 
1.67 2.25 1.423 
2.90 2.25 2.902 
2.90 4.95 2.903 
3.04 4.95 3.049 
@ 63.61 -50.45 
0 1.50 1.654 
3.42 1.50 1.875 
3.43 2.19 3.430 
5.31 2.19 1.032 
5.32 6.23 5.320 
5.43 6.23 5.434 

출력-1 (권장)

$ awk '/^@/{if(h){print h RS m}min=""; h=$0; next}min=="" || $3 < min{min=$3; m=$0}END{print h RS m}' infile 
@ 62.65 -50.35 
1.67 2.25 1.423 
@ 63.61 -50.45 
5.31 2.19 1.032 

출력-2

$ awk '/^@/{h=$0;min="";next}min==""||$3<min{min=$3;l[h]=$0}END{for(i in l)print i RS l[i]}' infile 
@ 62.65 -50.35 
1.67 2.25 1.423 
@ 63.61 -50.45 
5.31 2.19 1.032 
+1

다른 대답과 같은 주석 : 연관 배열의 키로 $ 0을 사용하는 것은 논쟁의 여지가 있습니다. 몇 개의 동일한 줄이 있다면? –

+0

@RenaudPacalet : 나는 당신과 동의하지만, 현재 상황에서 OP가 작은 데이터를 보여 주었기 때문에 이전에 덮어 쓰지 않을 첫 번째 해결책이 하나 더 있습니다. 필요한 복제본이 있는지 언급하지 않았습니다. 주의를 기울여서,'@'로 시작하는 고유 한 줄이있을 수 있다고 생각했습니다. –

1

awk는 다음과 같은 스크립트에 따라, 아주 쉽게이 작업을 수행 할 수 있습니다

awk ' 
    $1=="@" { first=1; key=$0; next } 
    first==1 { lowest=$3; line[key]=$0; first=0; next } 
       { if ($3 < lowest) { lowest=$3; line[key]=$0 } } 
    END  { for (key in line) { printf "%s\n%s\n", key, line[key] } } 
' <<EOF 
@ 62.65 -50.35 
0 1.50 1.676 
1.67 1.50 1.677 
1.67 2.25 1.423 
2.90 2.25 2.902 
2.90 4.95 2.903 
3.04 4.95 3.049 
@ 63.61 -50.45 
0 1.50 1.654 
3.42 1.50 1.875 
3.43 2.19 3.430 
5.31 2.19 1.032 
5.32 6.23 5.320 
5.43 6.23 5.434 
EOF 
요청으로

, 출력은 다음과 같습니다

@ 62.65 -50.35 
1.67 2.25 1.423 
@ 63.61 -50.45 
5.31 2.19 1.032 

설명에 대한 코드를 깨는 :

$1=="@" {    # For all header lines: 
    first=1    # Flag that you're starting a new block. 
    key=$0    # Save the key. 
    next     # Go back for next line. 
} 
first==1 {    # For first line in each block: 
    lowest=$3   # It must be lowest. 
    line[key]=$0   # Store line. 
    first=0    # Now processing subsequent lines in block. 
    next     # Go back for next line. 
} 
{      # For non-first-lines-in-block: 
    if ($3 < lowest) { # Only if this one is lower. 
     lowest=$3  # Store value and line. 
     line[key]=$0 
    } 
} 
END {     # At end, simply output associative array. 
    for (key in line) { 
     printf "%s\n%s\n", key, line[key] 
    } 
} 

이이 헤더 행이 고유 가정 명심하십시오. 중복이있을 수 있고이를 명확하게 처리하려면 NR$0의 조합으로 키를 생성 할 수 있습니다.

+0

오, 멋져요! 정말 고맙습니다! 정말 큰 도움이됩니다. :) – IsiSa

+1

연관 어레이의 키로'$ 0 '을 사용하는 것은 논쟁의 여지가 있습니다 : 몇 개의 동일한 라인이 있다면? –

+0

@RenaudPacalet :'$ 0'과 함께'NR'을 사용할 수 있습니다. 줄을 복제 할 수 있다고하더라도 각 블록을 고유하게 식별합니다. 나는 그것을 옵션으로 추가 할 것이다. – paxdiablo

1

완전히 다른 awk 접근 방식입니다.

awk 'BEGIN {RS="@"} {s=$3 OFS $4 OFS $5; n=$5; for (i=5;i<=NF;i+=3) {if ($i<n) {s=$(i-2) OFS $(i-1) OFS $i; n=$5} }} n { print "@ " $1 OFS $2 ORS s }' infile 

또는 쉽게 주석에 대한 세분화 :

BEGIN { 
    RS="@"       # "@" as our record separator 
} 

{ 
    s=$3 OFS $4 OFS $5    # store the first line... 
    n=$5 
    for (i=5;i<=NF;i+=3) {   # for each 3rd field on a line, 
    if ($i<n) {     # test its value and 
     s=$(i-2) OFS $(i-1) OFS $i # store a new value if the 
     n=$5      # condition matches 
    } 
    } 
} 

n { 
    print "@ " $1 OFS $2 ORS s  # print records once we have them. 
} 
0

이 다음은 아직 awk 명령을 사용하여 다른 솔루션입니다.

@ (B)가 (정의되지 않은 첫 번째 줄의 a와 b에)를 인쇄를 정의 된 경우로 시작하는 라인

인쇄 라인에 대한

awk ' 
/^@/{if(b)print a;print $0;next} 
!b||$3<b{b=$3;a=$0} 
END{print a} 
' infile 

/^@/{if(b)print a;print $0;next} 

및 다음 줄

로 이동
!b||$3<b{b=$3;a=$0} 

@ 의해 시작 라인은 B가 정의되지 않은 경우 whithout 라인마다

경우 또는 $ 3은 B에서 $ 3를 유지하고 마지막에

END{print a} 

의 라인을 유지, 우리는

+0

어떻게 작동합니까? 몇 가지 설명이 훌륭합니다. – ghoti

+0

@ghoti 설명을 위해 내 게시물을 업데이트합니다. –

관련 문제