如何在不影响文件格式的情况下更改文本文件中的行数组

How to change a array of rows in a text file without disturbing the format of the file

我有一个 DFT 代码 (VASP) 的输入文件 POSCAR,如下所示:

System
1.00000000000000
**5.2916193007999999    0.0000000000000000    0.0000000000000000
0.0000000000000000    5.2916193007999999    0.0000000000000000
0.0000000000000000    0.0000000000000000   20.0097122192000008**

       Ta   N
         2     4
    Direct
      0.0000000000000000  0.0000000000000000  0.5000000000000000
      0.5000000000000000  0.5000000000000000  0.5000000000000000
      0.1430930929177486  0.6430931269177513  0.5336780085877783
      0.8569068730822487  0.3569069180822488  0.5336780085877783
      0.6430931269177513  0.8569068730822487  0.4663219914122216
      0.3569069180822488  0.1430930929177486  0.4663219914122216

我想变形,或者我想说,我想更改一些具有特定百分比的参数,比如 0.5%,(这些以粗体显示)。 我们可以将粗体参数的数组命名为:

a11 a12 a13
a21 a22 a23
a31 a32 a33

根据具体情况,我需要将a11修改为a33(有时可能只有a11或a11修改为a13或全部为a)变形+0.5%,变形-0.5%

我的作业文件中需要一个 shell (bash) 脚本,以便生成所需的变形数据文件。

最终数据应该在两个目录中减去(它将有 a-a0.005)和加号((它将有 a+a0.005)。

最终数据应该是这样的:

在plus(mkdir plus)目录下,POSCAR文件应该是这个:

System
   1.00000000000000     
     5.3180773973039998995    1.0050000000000000000    1.4925000000000000000
     1.0050000000000000000    5.3180773973039998995    0.2010000000000000000
     1.4925000000000000000    0.2010000000000000000   10.0500000000000000000
   Ta   N
     2     4
Direct
  0.0000000000000000  0.0000000000000000  0.5000000000000000
  0.5000000000000000  0.5000000000000000  0.5000000000000000
  0.1430930929177486  0.6430931269177513  0.5336780085877783
  0.8569068730822487  0.3569069180822488  0.5336780085877783
  0.6430931269177513  0.8569068730822487  0.4663219914122216
  0.3569069180822488  0.1430930929177486  0.4663219914122216

在minus(mkdir minus)目录下,POSCAR文件应该是这个:

System
   1.00000000000000     
     5.2651612042959999005    0.9950000000000000000    1.4925000000000000000
     0.9950000000000000000    5.2651612042959999005    0.1990000000000000000
     1.4925000000000000000    0.1990000000000000000   9.9500000000000000000
   Ta   N 
     2     4
Direct
  0.0000000000000000  0.0000000000000000  0.5000000000000000
  0.5000000000000000  0.5000000000000000  0.5000000000000000
  0.1430930929177486  0.6430931269177513  0.5336780085877783
  0.8569068730822487  0.3569069180822488  0.5336780085877783
  0.6430931269177513  0.8569068730822487  0.4663219914122216
  0.3569069180822488  0.1430930929177486  0.4663219914122216

重要的是,直接下面出现的所有行都不会发生变化。

我正在尝试如下使用

#!/bin/bash
DEFORM=0.005
A11=$(cat POSCAR | head -n 3 | tail -n 1 | awk '{print }')
A12=$(cat POSCAR | head -n 3 | tail -n 1 | awk '{print }')
A13=$(cat POSCAR | head -n 3 | tail -n 1 | awk '{print }')
A21=$(cat POSCAR | head -n 4 | tail -n 1 | awk '{print }')
A22=$(cat POSCAR | head -n 4 | tail -n 1 | awk '{print }')
A23=$(cat POSCAR | head -n 4 | tail -n 1 | awk '{print }')
A31=$(cat POSCAR | head -n 5 | tail -n 1 | awk '{print }')
A32=$(cat POSCAR | head -n 5 | tail -n 1 | awk '{print }')
A33=$(cat POSCAR | head -n 5 | tail -n 1 | awk '{print }')
PA11=$(echo "$A11" "$DEFORM" | awk '{printf "%.16f\n",  +*}')
sed -i "s/$A11/$PA11/g" POSCAR

但这似乎是一个艰难的过程。我正在寻找一个简单的脚本。

我不熟悉这种文件格式,所以你得自己检查一下。

就awk而言,创建一个脚本(poscar.awk):

BEGIN{ DEFORM=0.005 }
NR>=3 && NR<=5{ 
  =-DEFORM 
  =-DEFORM 
  =-DEFORM 
  printf "         %.16f %.16f %.16f\n", , ,    # This prints lines 3-5
}
!(NR>=3 && NR<=5)                                     # This prints all other lines

然后您可以:awk -f poscar.awk inputfile 这将导致:

System
       1.00000000000000
         5.2866193008000000 0.9950000000000000 1.4950000000000001
         3.9950000000000001 5.2866193008000000 0.1950000000000000
         2.9950000000000001 0.2950000000000000 9.9949999999999992
       Ta   N
         2     4
    Direct
      0.0000000000000000  0.0000000000000000  0.5000000000000000
      0.5000000000000000  0.5000000000000000  0.5000000000000000
      0.1430930929177486  0.6430931269177513  0.5336780085877783
      0.8569068730822487  0.3569069180822488  0.5336780085877783
      0.6430931269177513  0.8569068730822487  0.4663219914122216
      0.3569069180822488  0.1430930929177486  0.4663219914122216

这可能是您正在尝试做的事情:

$ cat tst.awk
NR==1 {
    plus  = FILENAME "_plus"
    minus = FILENAME "_minus"
}
(3 <= NR) && (NR <= 5) {
    for (i=1; i<=NF; i++) {
        printf "%0.16f%s", $i * 1.005, (i<NF ? OFS : ORS) > plus
        printf "%0.16f%s", $i * 0.095, (i<NF ? OFS : ORS) > minus
    }
    next
}
{
    print > plus
    print > minus
}

$ awk -f tst.awk file

$ head -100 file_*
==> file_minus <==
System
1.00000000000000
0.5027038335760000 0.0000000000000000 0.0000000000000000
0.0000000000000000 0.5027038335760000 0.0000000000000000
0.0000000000000000 0.0000000000000000 1.9009226608240002

       Ta   N
         2     4
    Direct
      0.0000000000000000  0.0000000000000000  0.5000000000000000
      0.5000000000000000  0.5000000000000000  0.5000000000000000
      0.1430930929177486  0.6430931269177513  0.5336780085877783
      0.8569068730822487  0.3569069180822488  0.5336780085877783
      0.6430931269177513  0.8569068730822487  0.4663219914122216
      0.3569069180822488  0.1430930929177486  0.4663219914122216

==> file_plus <==
System
1.00000000000000
5.3180773973039992 0.0000000000000000 0.0000000000000000
0.0000000000000000 5.3180773973039992 0.0000000000000000
0.0000000000000000 0.0000000000000000 20.1097607802959999

       Ta   N
         2     4
    Direct
      0.0000000000000000  0.0000000000000000  0.5000000000000000
      0.5000000000000000  0.5000000000000000  0.5000000000000000
      0.1430930929177486  0.6430931269177513  0.5336780085877783
      0.8569068730822487  0.3569069180822488  0.5336780085877783
      0.6430931269177513  0.8569068730822487  0.4663219914122216
      0.3569069180822488  0.1430930929177486  0.4663219914122216