patternbashMinor
Parsing Gaussian09 frequency calculations, reformatting depending on desired output
Viewed 0 times
gaussian09frequencyoutputdesiredreformattingcalculationsparsingdepending
Problem
Quite similar to my earlier review this script parses a frequency calculation and reformats the found values to either fit into one row for easier importing into a spreadsheet software or a formatted table.
The whole project including sample calculation files for testing can be found on github. I checked the script with http://www.shellcheck.net/# and there were no warnings left. I am looking for some input, whether I could simplify some of the code or make it more efficient.
```
#!/bin/bash
# Script can be used to parse one (or more) frequency calculation(s)
# of the quantum chemical software suite Gaussian09
# Intitialise scriptoptions
errCount=0
printlevel=0
isOptimisation=0
isFreqCalc=0
ignorePrintlevelSwitch=0
# Initialise all variables that are of interest
declare filename functional temperature pressure
declare electronicEnergy zeroPointEnergy thermalCorrEnergy thermalCorrEnthalpy thermalCorrGibbs
declare -a contributionNames thermalE heatCapacity entropy
declare routeSection
# Errors, Info and Warnings
fatal ()
{
echo "ERROR : " "$@"
exit 1
}
message ()
{
echo "INFO : " "$@"
}
warn ()
{
echo "WARNING: " "$@"
}
# Parse the commands that have been passed to Gaussian09
getRouteSec ()
{
# The route section is echoed in the log file, but it might spread over various lines
# options might be cut off in the middle. It always starts with # folowed by a space
# or the various verbosity levels NPT (case insensitive). The route section is
# terminated by a line of dahes. The script will stop reading the file if encountered.
local line appendline
local addline=0
while read -r line; do
if [[ $line =~ ^[[:space:]]*#[nNpPtT]?[[:space:]] || "$addline" == "1" ]]; then
[[ $line =~ ^[[:space:]][-]+[[:space:]]$ ]] && break
appendline="$appendline$line"
addline=1
fi
done < "$filename"
routeSection="$appendline"
}
# Test the route section if it is an optimis
The whole project including sample calculation files for testing can be found on github. I checked the script with http://www.shellcheck.net/# and there were no warnings left. I am looking for some input, whether I could simplify some of the code or make it more efficient.
```
#!/bin/bash
# Script can be used to parse one (or more) frequency calculation(s)
# of the quantum chemical software suite Gaussian09
# Intitialise scriptoptions
errCount=0
printlevel=0
isOptimisation=0
isFreqCalc=0
ignorePrintlevelSwitch=0
# Initialise all variables that are of interest
declare filename functional temperature pressure
declare electronicEnergy zeroPointEnergy thermalCorrEnergy thermalCorrEnthalpy thermalCorrGibbs
declare -a contributionNames thermalE heatCapacity entropy
declare routeSection
# Errors, Info and Warnings
fatal ()
{
echo "ERROR : " "$@"
exit 1
}
message ()
{
echo "INFO : " "$@"
}
warn ()
{
echo "WARNING: " "$@"
}
# Parse the commands that have been passed to Gaussian09
getRouteSec ()
{
# The route section is echoed in the log file, but it might spread over various lines
# options might be cut off in the middle. It always starts with # folowed by a space
# or the various verbosity levels NPT (case insensitive). The route section is
# terminated by a line of dahes. The script will stop reading the file if encountered.
local line appendline
local addline=0
while read -r line; do
if [[ $line =~ ^[[:space:]]*#[nNpPtT]?[[:space:]] || "$addline" == "1" ]]; then
[[ $line =~ ^[[:space:]][-]+[[:space:]]$ ]] && break
appendline="$appendline$line"
addline=1
fi
done < "$filename"
routeSection="$appendline"
}
# Test the route section if it is an optimis
Solution
Use a for-each loop when the index is not needed
In this loop you don't really need the loop index:
Since you need just the elements, a for-each loop is more natural:
Do the same for the other counting loops too where possible.
Use here-string instead of redirecting
Instead of this:
Better to use a here-string to avoid an additional process creation:
Use modern
Since you used
A consistent writing style improves readability.
Simple scripts evolving into complex programs
This script is getting really complex. Bash is great for simple things, but when things start to get complex, it often becomes a wrestle. I would recommend Python as a scripting language for complex tasks. It has great unit testing facilities too.
In this loop you don't really need the loop index:
for (( index=0; index < ${#contributionNames[@]}; index++ )); do
printf "%-10s " "${contributionNames[$index]}"
doneSince you need just the elements, a for-each loop is more natural:
for name in "${contributionNames[@]}"; do
printf "%-10s " "$name"
doneDo the same for the other counting loops too where possible.
Use here-string instead of redirecting
echoInstead of this:
fold -w80 -c -s < <(echo "$routeSection")Better to use a here-string to avoid an additional process creation:
fold -w80 -c -s <<< "$routeSection"Use modern
(( ... )) consistentlySince you used
(( ... )) a lot, I don't understand why you didn't use it here:if [ ${#values[$index]} -lt ${#header[$index]} ]; then-lt is old-fashioned, you could use naturally < in a (( ... )).A consistent writing style improves readability.
Simple scripts evolving into complex programs
This script is getting really complex. Bash is great for simple things, but when things start to get complex, it often becomes a wrestle. I would recommend Python as a scripting language for complex tasks. It has great unit testing facilities too.
Code Snippets
for (( index=0; index < ${#contributionNames[@]}; index++ )); do
printf "%-10s " "${contributionNames[$index]}"
donefor name in "${contributionNames[@]}"; do
printf "%-10s " "$name"
donefold -w80 -c -s < <(echo "$routeSection")fold -w80 -c -s <<< "$routeSection"if [ ${#values[$index]} -lt ${#header[$index]} ]; thenContext
StackExchange Code Review Q#131666, answer score: 3
Revisions (0)
No revisions yet.