행에 패턴이 포함되어 있으면 변수를 열에 인쇄합니다.

행에 패턴이 포함되어 있으면 변수를 열에 인쇄합니다.

나는 파일을 가지고 있습니다 DEMLIR-GEO_OPT-1-distance-1.coordLog:

 REQUESTED STRUCTURE DATA

  Distance vector r(i,j) between the atom i and j in ANGSTROM

  r(1,5)           =     0.944776     0.190651     1.602108   |r| =     1.869679
  r(2,5)           =    -0.693580    -0.927860    -1.000974   |r| =     1.530989
  r(2,8)           =     1.618580     0.570765    -0.688275   |r| =     1.849134

 REQUESTED STRUCTURE DATA

  Distance vector r(i,j) between the atom i and j in ANGSTROM

  r(1,5)           =     0.945905     0.187745     1.601950   |r| =     1.869821
  r(2,5)           =    -0.692409    -0.928976    -1.001505   |r| =     1.531483
  r(2,8)           =     1.618487     0.572023    -0.688769   |r| =     1.849626

 REQUESTED STRUCTURE DATA

  Distance vector r(i,j) between the atom i and j in ANGSTROM

  r(1,5)           =     0.946708     0.186226     1.601724   |r| =     1.869881
  r(2,5)           =    -0.691970    -0.929421    -1.002033   |r| =     1.531900
  r(2,8)           =     1.618395     0.572685    -0.688576   |r| =     1.849678

파일의 각 줄을 읽고 패턴이 포함되어 있으면 r(1,5)다음 값을 인쇄하고 싶습니다 |r| =. 지금까지 다음 코드를 작성했습니다.

    #!/bin/bash

    set -o errexit
    set -o nounset
    set -o pipefail


  exec 0<"DEMLIR-GEO_OPT-1-distance-1.coordLog"
     while read -r line
     do
     for j in $(seq 0 2)
     do
     if [[ "$line" == *"r(1,5)"* ]] ; then
             dist1=$(gawk 'BEGIN{FS="|r| ="} {print $2}' | tr -s " ")
        elif [[ "$line" == *"r(2,5)"* ]] ; then
                dist2=$(gawk 'BEGIN{FS="|r| ="} {print $2}' | tr -s " ")
        elif [[ "$line" == *"r(2,8)"* ]] ; then
                dist3=$(gawk 'BEGIN{FS="|r| ="} {print $2}' | tr -s " ")
     fi


     printf "%-3f %-3f %-3f %-3f\n" "1.$j" "$dist1" "$dist2" "$dist3"

     done
     done>DEMLIR_task.txt

하지만 다음과 같은 오류가 발생합니다.

dist1: unbound variable

1.0 라인에는 도달하지 않지만 "1.$j"오류도 발생한다는 것을 알고 있습니다.

나는 또한 sed내가 원하는 것을 얻으려고 노력했는데, 그것은 다음과 같습니다:

sed -n '/r(1,5)/p' DEMLIR-GEO_OPT-1-distance-1.coordLog> new
sed -i 's/^.*|r| =//' new

그러면 새 파일에 그 이후의 값이 인쇄되고 |r| =, if 문에서 볼 수 있듯이 다른 두 조건에 대해서도 동일한 작업을 수행해야 한다는 점을 고려하면 필요하지 않은 파일이 너무 많아지게 됩니다. 나는 그것을 원하지 않습니다.

나는 첫 번째 작업 방식을 원합니다. 어떻게 해야 합니까?

편집하다

r(1,5)0,1,2의 거리를 첫 번째 열, 두 번째, r(2,5)세 번째, 네 번째 열에 인쇄 하고 싶습니다. 새 파일을 만들거나 원본 파일을 변경하지 않고 이 작업을 수행하고 싶습니다. 내가 원하는 출력은 다음과 같습니다.r(2,8)DEMLIR_task.txt

0 1.869679 1.530989 1.849134
1 1.869821 1.531483 1.849626
2 1.869881 1.531900 1.849678

답변1

가능한 솔루션은 awk에만 있습니다. 나는 하나를 만들었습니다 prg.awk:

BEGIN { j=0; }
{
    if ( $1 == "r(1,5)" )
    {
        dist1=$8;
    }
    if ( $1 == "r(2,5)" )
    {
        dist2=$8;
    }
    if ( $1 == "r(2,8)")
    {
        dist3=$8;
        print j": "dist1" "dist2" "dist3;
        ++j;
    }
}

콘텐츠 file.txt:

yurijs-MacBook-Pro:bash yurij$ cat ./file.txt
REQUESTED STRUCTURE DATA

  Distance vector r(i,j) between the atom i and j in ANGSTROM

  r(1,5)           =     0.944776     0.190651     1.602108   |r| =     1.869679
  r(2,5)           =    -0.693580    -0.927860    -1.000974   |r| =     1.530989
  r(2,8)           =     1.618580     0.570765    -0.688275   |r| =     1.849134

 REQUESTED STRUCTURE DATA

  Distance vector r(i,j) between the atom i and j in ANGSTROM

  r(1,5)           =     0.945905     0.187745     1.601950   |r| =     1.869821
  r(2,5)           =    -0.692409    -0.928976    -1.001505   |r| =     1.531483
  r(2,8)           =     1.618487     0.572023    -0.688769   |r| =     1.849626

 REQUESTED STRUCTURE DATA

  Distance vector r(i,j) between the atom i and j in ANGSTROM

  r(1,5)           =     0.946708     0.186226     1.601724   |r| =     1.869881
  r(2,5)           =    -0.691970    -0.929421    -1.002033   |r| =     1.531900
  r(2,8)           =     1.618395     0.572685    -0.688576   |r| =     1.849678

프로그램을 실행합니다:

yurijs-MacBook-Pro:bash yurij$ awk -f prg.awk ./file.txt
0: 1.869679 1.530989 1.849134
1: 1.869821 1.531483 1.849626
2: 1.869881 1.531900 1.849678

답변2

그리고 sed, echo그리고 tr:

$ se () { echo -n "$1 "; sed -n 's/\s*r('"$2"').*|r| =\s\+//p' DEMLIR-GEO_OPT-1-distance-1.coordLog | tr '\n' ' '; echo; }
$ se 0 1,5; se 1 2,5; se 2 2,8
0 1.869679 1.869821 1.869881
1 1.530989 1.531483 1.531900
2 1.849134 1.849626 1.849678

# using a for-loop
cnt=0; for i in 1,5 2,5 2,8; do se $((cnt++)) $i; done

출력을 파일에 쓰려면 다음을 사용할 수 있습니다.

{ se 0 1,5; se 1 2,5; se 2 2,8; } > DEMLIR_task.txt

순서가 잘못된 경우 , 및 다음을 사용하여 이 코드 조각을 사용할 수 있습니다 sed.pasteprintf

$ se () { sed -n 's/\s*r('"$1"').*|r| =\s\+//p' DEMLIR-GEO_OPT-1-distance-1.coordLog; }
$ paste -d' ' <(printf '%s\n' 0 1 2) <(se 1,5) <(se 2,5) <(se 2,8)
0 1.869679 1.530989 1.849134
1 1.869821 1.531483 1.849626
2 1.869881 1.531900 1.849678

# using a for-loop and temp files, first column starts with 1 instead of 0
rm -f tmp.*; cnt=0; for i in 1,5 2,5 2,8; do se $i > tmp.$((cnt++)); done; paste -d ' ' tmp.* | cat -n

답변3

셸 옵션을 dist1: unbound variable설정했기 때문에 오류 메시지가 나타납니다 . 그런 다음 변수를 설정하기 전에 사용할 nounset수 있습니다 .dist1


/REQUESTED STRUCTURE DATA/ { ++n; m = 0 }

$6 == "|r|" { r[n,++m] = $NF }

END {
    for (j = 1; j <= m; ++j) {
        $0 = j - 1
        for (i = 1; i <= n; ++i)
            $(i + 1) = r[i,j]

        print
    }
}

(예를 들어 출력을 awk ... >DEMLIR_task.txt새 파일에 저장하기 위해 리디렉션하는 데 사용)

데이터는 여러 부분으로 나누어지며, 각 부분은 행으로 시작 REQUESTED STRUCTURE DATA하고 많은 레코드를 포함합니다. 해당 레코드는 |r|6번째 필드의 문자열을 검색하여 찾을 수 있습니다.

awk프로그램은 각 행 앞에 카운터가 있는 열 섹션에 있는 각 레코드의 마지막 필드에서 수집된 숫자를 출력합니다. 각 부분( m코드의)에는 임의의 수의 레코드가 있을 수 있고 입력 데이터( n코드의)에는 임의의 수의 부분이 있을 수 있다고 가정합니다 .

시험:

$ awk -f script.awk file
0 1.869679 1.869821 1.869881
1 1.530989 1.531483 1.531900
2 1.849134 1.849626 1.849678

관련 정보