The ORCA examples are ORCA 6 outputs from the ORCA guide. opt.out is a B3LYP-D4/def2-TZVP optimisation + frequency run on water. The QE and LAMMPS examples are also real outputs, produced while writing those guides. grep, sed and awk syntax is covered in the previous chapter.

ORCA: the final energy

ORCA writes a FINAL SINGLE POINT ENERGY line every time it computes an energy. An optimisation prints one per cycle, so you want the last one.

$ grep 'FINAL SINGLE POINT ENERGY' opt.out
FINAL SINGLE POINT ENERGY       -76.426286364586
FINAL SINGLE POINT ENERGY       -76.426353431114
FINAL SINGLE POINT ENERGY       -76.426364583348
FINAL SINGLE POINT ENERGY       -76.426366351564
FINAL SINGLE POINT ENERGY       -76.426369457144
$ grep 'FINAL SINGLE POINT ENERGY' opt.out | tail -1 | awk '{print $5}'
-76.426369457144

awk alone works too: overwrite a variable on every matching line and print it in END, and the last value is what remains. If no line matches you get an empty line, so check for an empty result in scripts.

$ awk '/FINAL SINGLE POINT ENERGY/ {e = $5} END {print e}' opt.out
-76.426369457144

ORCA: energy per optimisation cycle

To plot the convergence, save cycle number and energy as two columns. gnuplot and matplotlib read this directly.

$ grep 'FINAL SINGLE POINT ENERGY' opt.out | awk '{printf "%d %.10f\n", NR, $5}' > scf.dat
$ cat scf.dat
1 -76.4262863646
2 -76.4263534311
3 -76.4263645833
4 -76.4263663516
5 -76.4263694571

The five lines are the four optimisation cycles and the final evaluation at the converged geometry. A third column with the energy relative to the last value, in kcal/mol, shows how much was left to converge. Collect all values in an array and compute in END.

$ awk '/FINAL SINGLE POINT ENERGY/ {n++; e[n] = $5}
       END {for (i = 1; i <= n; i++) printf "%d %.10f %8.4f\n", i, e[i], (e[i] - e[n]) * 627.5095}' opt.out
1 -76.4262863646   0.0521
2 -76.4263534311   0.0101
3 -76.4263645833   0.0031
4 -76.4263663516   0.0019
5 -76.4263694571   0.0000

ORCA: normal termination and convergence

Before using a number, check that the job ran to the end. A finished ORCA output ends with ORCA TERMINATED NORMALLY, and a converged optimisation prints THE OPTIMIZATION HAS CONVERGED. 05-killed is a copy of an output cut off partway, to stand in for a job killed at the walltime limit.

$ grep -c 'ORCA TERMINATED NORMALLY' opt.out
1
$ grep -c 'ORCA TERMINATED NORMALLY' jobs/05-killed/water.out
0
$ grep -q 'THE OPTIMIZATION HAS CONVERGED' opt.out && echo converged || echo 'NOT converged'
converged

grep -q prints nothing and only sets the exit status: 0 if found, 1 if not. That makes it usable directly in an if.

ORCA: imaginary frequencies and free energy

The frequencies sit between VIBRATIONAL FREQUENCIES and NORMAL MODES. An awk range pattern /start/,/end/ cuts out that block, and the second column holds the values.

$ awk '/VIBRATIONAL FREQUENCIES/,/NORMAL MODES/' opt.out | awk '/cm\*\*-1/ {print $2}'
0.00
0.00
0.00
0.00
0.00
0.00
1615.68
3780.78
3885.42

The first six zeros are translations and rotations. ORCA prints imaginary frequencies as negative numbers followed by ***imaginary mode***. The command below prints and counts the negative lines inside the block. ts.out is a copy in which mode 6 was edited to a negative value, as in the ORCA guide example, to show the format.

$ awk '/VIBRATIONAL FREQUENCIES/ {f = 1} /NORMAL MODES/ {f = 0}
       f && /cm\*\*-1/ && $2 < 0 {n++; print}
       END {print n + 0, "imaginary"}' opt.out
0 imaginary
$ awk '/VIBRATIONAL FREQUENCIES/ {f = 1} /NORMAL MODES/ {f = 0}
       f && /cm\*\*-1/ && $2 < 0 {n++; print}
       END {print n + 0, "imaginary"}' ts.out
     6:    -456.78 cm**-1   ***imaginary mode***
1 imaginary

n + 0 makes a variable that was never incremented print as 0 instead of an empty string. Thermochemistry results are single labelled lines, so grep and awk get them directly.

$ grep 'Final Gibbs free energy' opt.out
Final Gibbs free energy         ...    -76.42286885 Eh
$ awk '/Final Gibbs free energy/ {print $6}' opt.out
-76.42286885

ORCA: last geometry to xyz

A CARTESIAN COORDINATES (ANGSTROEM) block is printed every cycle. Skip the dashed line after the header and collect coordinates until the next blank line. Each new block resets the counter, so only the last block is left at the end.

awk '/CARTESIAN COORDINATES \(ANGSTROEM\)/ {getline; n = 0; blk = 1; next}
     blk && NF == 0 {blk = 0}
     blk {line[++n] = $0}
     END {print n; print "final geometry"; for (i = 1; i <= n; i++) print line[i]}' opt.out > final.xyz
$ cat final.xyz
3
final geometry
  O      0.000000    0.000000    0.111489
  H      0.000000    0.765189   -0.473160
  H      0.000000   -0.765189   -0.473160

Parentheses in the regex are escaped as \(. getline reads (and so skips) the next line. ORCA also saves the optimised geometry as inputname.xyz; this recipe is for when only the output file is left.

Many jobs into one CSV table

Suppose each calculation has its own directory with an output inside. Skip unfinished jobs, collect the energies of the rest and add energies relative to the lowest one (1 Eh = 627.5095 kcal/mol).

#!/bin/bash
# collect.sh: final energy of every job directory into a CSV
set -euo pipefail

echo "name,energy_Eh" > energies.csv
for out in jobs/*/*.out; do
    name=$(basename "$(dirname "$out")")
    if ! grep -q 'ORCA TERMINATED NORMALLY' "$out"; then
        echo "skip $name: not finished" >&2
        continue
    fi
    e=$(awk '/FINAL SINGLE POINT ENERGY/ {e = $5} END {print e}' "$out")
    echo "$name,$e" >> energies.csv
done

awk -F, 'NR > 1 {name[NR] = $1; e[NR] = $2; if (NR == 2 || $2 < min) min = $2}
         END {print "name,energy_Eh,rel_kcal"
              for (i = 2; i <= NR; i++) printf "%s,%.8f,%.2f\n", name[i], e[i], (e[i] - min) * 627.5095}' \
    energies.csv > table.csv
$ bash collect.sh
skip 05-killed: not finished
$ column -t -s, table.csv
name              energy_Eh     rel_kcal
01-single-point   -76.32127441  65.95
02-opt-freq       -76.42636946  0.00
03-dlpno-ccsdt    -76.33195934  59.24
04-solvation-smd  -76.33297155  58.61

These four jobs are the same water molecule at different levels of theory, so the relative energies mean nothing chemically. The one meaningful comparison is gas phase (01) versus SMD water (04) at the same B3LYP/def2-SVP level: −7.34 kcal/mol. In practice you run this script over directories of isomers or conformers computed with one method.

Files that came from Windows

Files created on or copied through Windows can have CRLF (\r\n) line endings. The last field then carries a \r, invisible characters end up in your CSV, and $ anchors stop matching. If cat -A file shows ^M at the line ends, fix it with tr -d '\r' < old > new or dos2unix.

Quantum ESPRESSO

pw.x prints total energy at every SCF iteration and marks only the converged value with a leading !, so searching for ^! skips the intermediate values. Below is the silicon SCF example output from the QE guide. Energies are in Ry; 1 Ry = 13.605693 eV.

$ grep '^!' si.scf.out
!    total energy              =     -93.45273690 Ry
$ grep '^!' si.scf.out | tail -1 | awk '{printf "%.8f Ry = %.6f eV\n", $5, $5 * 13.605693}'
-93.45273690 Ry = -1271.489248 eV
$ grep -c 'convergence has been achieved' si.scf.out
1
$ grep -c 'convergence NOT achieved' si.scf.out
0
$ grep 'JOB DONE' si.scf.out
   JOB DONE.

A vc-relax runs a new SCF at every ionic step, so there are several ! lines. The pressure is the last field of the P= lines.

$ grep '^!' si.vcrelax.out | awk '{printf "%d %.8f\n", NR, $5}'
1 -93.44443849
2 -93.45157833
3 -93.45321788
4 -93.45325068
5 -93.45325084
6 -93.45327391
$ grep 'P=' si.vcrelax.out | awk '{print $NF}'
108.71
43.06
5.66
0.39
0.00
-0.03
$ grep -E 'bfgs converged|Final enthalpy' si.vcrelax.out
     bfgs converged in   5 scf cycles and   4 bfgs steps
     Final enthalpy           =     -93.4532508364 Ry

The sixth value is an extra SCF run on the final cell after BFGS finishes. A new cell means a new plane-wave basis, so the value shifts slightly. Report Final enthalpy as the result of the relaxation; a large gap between the two suggests the cutoff is too low.

LAMMPS thermo table

In log.lammps, thermo output sits between a header line starting with Step and a Loop time line. Each run command adds another such block. This is the Cu slab log from the LAMMPS guide, with a 10000-step equilibration and a 5000-step production run.

$ awk '$1 == "Step" {on = 1; next} /^Loop time/ {on = 0} on' log.lammps | head -4
         0   253.8184      -5749.9163     -5695.3556     -5778.9907    
       500   253.05769     -5694.4003     -5640.0031     -9546.1221    
      1000   267.19235     -5695.7562     -5638.3206      1729.171     
      1500   253.1248      -5692.6357     -5638.2241     -9774.9528    

The header is indented, so /^Step/ would miss it. Comparing the first field with $1 == "Step" works regardless of leading spaces. Keeping the header once as a # comment gives a file that numpy's loadtxt and gnuplot read as is.

$ awk '$1 == "Step" {on = 1; if (!hdr++) print "#", $0; next} /^Loop time/ {on = 0} on' log.lammps > thermo.dat
$ head -3 thermo.dat
#    Step          Temp          PotEng         TotEng         Press     
         0   253.8184      -5749.9163     -5695.3556     -5778.9907    
       500   253.05769     -5694.4003     -5640.0031     -9546.1221    

The two blocks are concatenated and the step count restarts at 0 (this input calls reset_timestep 0 before production). To keep only the production run, count headers and switch on only in the second block.

$ awk '$1 == "Step" {run++; on = (run == 2); next} /^Loop time/ {on = 0} on' log.lammps | head -3
         0   247.4071      -5695.3154     -5642.1329     -4114.9433    
       500   254.87546     -5696.5557     -5641.7678     -4072.5059    
      1000   242.9701      -5696.8721     -5644.6433     -4897.1177    

xtb

xtb prints the same energy in two summary boxes. Below are xtb 6.7.1 outputs of a GFN2-xTB single point on water (xtb_sp.out) and an optimisation of methanol (xtb_opt.out). The TOTAL ENERGY line appears only once, at the end, so in an optimisation output it is the final value.

$ grep -E ':: total energy|TOTAL ENERGY' xtb_sp.out
         :: total energy              -5.070222286727 Eh    ::
          | TOTAL ENERGY               -5.070222286727 Eh   |
$ awk '/TOTAL ENERGY/ {print $4}' xtb_opt.out
-8.226118421023
$ grep 'GEOMETRY OPTIMIZATION CONVERGED' xtb_opt.out
   *** GEOMETRY OPTIMIZATION CONVERGED AFTER 5 ITERATIONS ***

xtb writes normal termination of xtb to standard error, not standard output. With only xtb mol.xyz > sp.out that line never reaches the file; save both streams with > sp.out 2>&1 if you want to check for it.

When to switch to Python

grep and awk are right for one or two numbers. For data spread over several blocks (normal-mode vectors, atomic charges, orbital energies), or sections whose format changes between program versions, a parser library breaks less often. cclib reads ORCA, Gaussian and other quantum chemistry outputs into numpy arrays, and ASE's ase.io.read handles most structure formats, including QE outputs and LAMMPS dumps.