如果行包含模式,则将变量打印到列

如果行包含模式,则将变量打印到列

我有文件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| =,并且考虑到我必须对其他 2 个条件执行相同的操作,正如您在 if 语句中看到的那样,我最终会得到太多不需要的文件。我不想那样。

我想要第一种工作方式。我应该怎么办?

编辑

我想在名为 的新文件中打印 0,1,2 到第一列,r(1,5)到第二列、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,echotr:

$ 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,paste和来使用此代码片段printf

$ 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因为您设置了nounsetshell 选项。然后,您可以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
    }
}

(使用eg重定向输出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

相关内容