0

I am trying to get data from a file that is like this:

  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

I want to take always the fourth column from the 6 line (1.95329810 in this case), then look for its closest value in the following lines, from the first column(1.877 in this case). That only for referencing, after founding that, I want to extract the next line which its second column is non zero (4.152).

So I would like to get 1.95329810 and 4.152 as output, so I can substract them and get:

band_gap=4.152-$fermi_energy

By taking in consideration @DopeGhoti s answer, I used his code with an if statement:

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

Where the go.awk file is:

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
   }
}

But I think that it is not the right way to use bash variables inside an awk script.

P.D. In the case you are wondering, the data represents the calculations of the Density Of States of the electrons of an oxide. The first column represents the electron's energies, the second the electron's amount in that energy level. Therefore, when looking for the next non '0.0000E+00' value since the closest level of the Fermi Energy, we can calculate the energy required to make the electrons jump and conduct electricity. (Metals have zero band gap, thus they do not need energy input to conduct electricity)

  • awk 'NR==6 {fermi_energy=$4}; /1.877/ {print $1-fermi_energy}', but I don't think this solves your problem. Given the input file above, what would be the expected output? What makes 1.877 special (why do you need to take the value from there)? What is special about 4.152, are there more values to follow? – nohillside Feb 26 '18 at 19:59
  • Printing 1.877 on a line that contains 1.877 is just /1.877/ {print "1.877"} . But I really assume the numbers you mention aren't constants, but that there's some other rule you want to use. Why don't you tell what the actual logic is. It's also probably easier to implement all of this in awk instead of mixing awk and the shell – ilkkachu Feb 26 '18 at 20:19
  • 2
    Also, show what output you want to see – glenn jackman Feb 26 '18 at 20:23
  • Sorry for the bad explanation of the problem. I edited the question. – Joshua Salazar Feb 27 '18 at 6:53
  • 1
    The correct way to use a bash variable within an awk script would be e. g. foo="foo bar"; awk -v foo="$foo" ' END { print foo }'. awk doesn't inherit environment variables from bash, you have to explicitly set them. – DopeGhoti Mar 1 '18 at 21:39
2

This seems to do what you appear to want, given the lack of sample output:

awk 'NF == 3 && $2 != "0.0000E+00" { print $1 }' /path/to/input
1.726
1.877
4.152
4.303
4.455

If you are actually asking for the first field on the last line where the second field is not (mathematically) zero which is followed by a record where the second field is (mathematically) zero, followed only by the first field of the first subsequent record where the second field is again not (mathematically) zero.. this is also doable with a relatively simple awk script:

$ cat 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" {
  print $1
  test=0
}
$ awk -f go.awk input
1.877
4.152
  • That helped a lot! Now I learned something... but it was not (yet) my desired output. I edited the question. – Joshua Salazar Feb 27 '18 at 6:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.