在 awk 脚本中使用 if 和 shell 变量

在 awk 脚本中使用 if 和 shell 变量

我正在尝试从如下文件中获取数据:

  6   6   1   0
  0.1166667E+02  0.4826611E-09  0.4826611E-09  0.3004786E-09  0.5000000E-15
  1.000000000000000E-004
  CAR 
 system-001                       
     10.51965443    -34.96542345  301      1.95329810      1.00000000
-15.558  0.1631E+01  0.1597E+02
-15.407  0.1661E+02  0.1779E+02
-15.255  0.4253E+01  0.1990E+02
-15.104  0.0000E+00  0.2000E+02
-14.952  0.0000E+00  0.2000E+02
 -3.884  0.0000E+00  0.2000E+02
 -3.732  0.0000E+00  0.2000E+02
 -3.581  0.0000E+00  0.2000E+02
 -3.429  0.0000E+00  0.2000E+02
 -3.277  0.8214E-03  0.2000E+02
 -3.126  0.3543E+00  0.2002E+02
  1.726  0.1019E+01  0.4386E+02
  1.877  0.5581E+00  0.4399E+02
  2.029  0.0000E+00  0.4400E+02
  2.181  0.0000E+00  0.4400E+02
  2.332  0.0000E+00  0.4400E+02
  2.484  0.0000E+00  0.4400E+02
  2.636  0.0000E+00  0.4400E+02
  2.787  0.0000E+00  0.4400E+02
  2.939  0.0000E+00  0.4400E+02
  3.090  0.0000E+00  0.4400E+02
  3.242  0.0000E+00  0.4400E+02
  3.394  0.0000E+00  0.4400E+02
  3.545  0.0000E+00  0.4400E+02
  3.697  0.0000E+00  0.4400E+02
  3.849  0.0000E+00  0.4400E+02
  4.000  0.0000E+00  0.4400E+02
  4.152  0.6271E-01  0.4400E+02
  4.303  0.4520E+01  0.4433E+02
  4.455  0.5040E+01  0.4511E+02

我想始终从第 6 行获取第四列(在本例中为 1.95329810),然后在以下几行中从第一列(在本例中为 1.877)查找其最接近的值。这仅供参考,找到后,我想提取第二列非零的下一行(4.152)。

所以我想得到 1.95329810 和 4.152 作为输出,这样我就可以减去它们并得到:

band_gap=4.152-$fermi_energy

考虑到 @DopeGhoti 的回答,我将他的代码与 if 语句一起使用:

#!/bin/bash
fermi_energy=$(awk 'NR==6 {printf $4}' DOSCAR-62.4902421.st)
awk -f go.awk DOSCAR-62.4902421.st

文件所在位置go.awk

BEGIN { 
test=0
}
NF == 3 && test == 0 && $2 != "0.0000E+00" {
   keptvalue=$1
}
NF == 3 && test == 0 && $2 == "0.0000E+00" {
   #print keptvalue
   test=1
}
NF == 3 && test == 1 && $2 != "0.0000E+00" {
   if ( sqrt(($fermi_energy-$1)**2) < 0.5 ) 
   {
       print $1
       test=0
   }
}

但我认为这不是在 awk 脚本中使用 bash 变量的正确方法。

PD如果您想知道,数据代表计算状态密度氧化物的电子。第一列代表电子的能量,第二列代表该能级中电子的数量。因此,当寻找自最接近级别以来的下一个非“0.0000E+00”值时费米能源,我们可以计算出电子跳跃和导电所需的能量。 (金属具有零带隙,因此不需要能量输入即可导电)

答案1

下面的答案对你的技术进行了一些改变。

  1. 在一个awk程序而不是两个程序中完成这一切。您可以这样做,因为您的第二次运行仅处理第 6 行之后的行:

  2. 正确分配第 6 行中的 fermi_energy 值。

  3. 不再需要检查,NF==3因为全部第 6 行之后的行满足该标准。

  4. 消除变量test,而是让我们保留fermi_energy和之间的最小差异的运行选项卡$1。为此,我们将创建一个变量min,该变量最初具有一个大得离谱的值,保证第一次测试失败。我们还将为其他变量分配易于理解的名称,并在测试文件的所有行后仅打印一个结果。

  5. 将计算量大的绝对值测试替换为计算量小的零测试。

  6. 注意awk支持浮点科学记数法。例如,在printf命令中,可以使用格式%E.像往常一样,请查看该man页面或您最喜欢的搜索引擎以了解更多信息。

  7. 所有这些都是在不了解粒子物理学的情况下完成的,所以我可能得到了一些不正确的东西。赦免。如果是这样,我希望至少这能让你走上正轨。

    awk '
        BEGIN  { min=1000 ; jump_energy="INIT" }
        function abs(v) {return v < 0 ? -v : v}
        NR==6 {fermi_energy=$4}
        NR>6 {
            if (jump_energy != 0) {
                this_diff=abs(fermi_energy-$1)
                if (this_diff < min) {
                    min=this_diff
                    energy_level=0
                    jump_energy=0
                    getline
                }
            }
            if (jump_energy == 0  && $2 != "0.0000E+00") {
                energy_level=$1
                jump_energy=$2
            }
        }
        END {
            printf "  Fermi Energy: %f\n  Energy Level: %f\n  Jump Energy: %E\n", fermi_energy, energy_level, jump_energy
        }'
    

答案2

awk 'NR == 6 { fe = $4 }
     NR > 6 && $1 > fe && $2 > 0 { print fe, $1; exit }' file

对于给定的输入数据,file将产生

1.95329810 4.152

awk脚本忽略前五行输入。在第六行,它挑选出第四个字段并将其分配给变量fe(简称“费米能量”)。

然后,代码假设第一列中的值正在增加,并且当第一列值中的第一个值达到高于存储在 中的值时fe,如果第二列非零,则打印出fe第一列中的值列和出口。

不幸的是,我不完全了解您的较长代码段,因为没有解释您实际想要它做什么。

相关内容