Skrypt Bash do automatyzacji obliczeń HPC

Sep 01 2020

Jestem studentem chemii i pracuję nad prostym skryptem bash do zautomatyzowania obliczeń teorii funkcjonalnej gęstości HPC przy użyciu Quantum Espresso (pw.x). Jestem bardzo nowicjuszem w tworzeniu skryptów powłoki i byłbym wdzięczny za krytykę / opinie, zanim spróbuję zaimplementować je w klastrze. Skrypt wywołuje in-gen.py, który jest skryptem w Pythonie, który napisałem do generowania nowych plików wejściowych, jeśli określone progi parametrów w pliku dziennika nie są spełnione.

#!/bin/bash
    
#SBATCH --job-name=2x2x6_PbCO3          # job name        
#SBATCH --output=slurm.out              # Output file name                                                                                                                                                
#SBATCH --error=slurm.err               # Error file name                                                                                                                                                 
#SBATCH --partition=batch               # Partition                                                                                                                                                       
#SBATCH --qos=medium+                   # Queue                                                                                                                                                           
#SBATCH --time=24:00:00                 # Time limit                                                                                                                                                      
#SBATCH --nodes=3                       # Number of nodes                                                                                                                                                 
#SBATCH --ntasks-per-node=16            # MPI processes per node 

errors='MPI_ABORT|error|aborted|SIGTERM|TIME|CANCELLED|SIGCONT|terminated|fork'
job='2x2x6_PbCO3'
max_runs=5
prefix=PbCO3

#-------------------------------------------------------------------------------
Clear () 
{
# Checks for input/log from a completed batch script
if [[ -f "$prefix.in" && -f "$prefix.log"  ]]; then
   # If both are found a new input file is generated
   python ~/path-to-in-gen.py $prefix.log $prefix.in $job override if [ -z "$(ls -A ../logs_and_inputs)" ]; then
      index=1
   else
      indices=()
      # Old input/log are tagged and stored
      for entry in "../logs_and_inputs"/$prefix.in-*; do indices+=("${entry: -1}")
      done
      max=${indices[0]} for n in "${indices[@]}" ; do
         ((n > max)) && max=$n done index=$((max+1))
      rm -r *x*x*
      mv $prefix.in ../logs_and_inputs/$prefix.in-$index mv $prefix.log ../logs_and_inputs/$prefix.log-$index
      mv $prefix.in-new $prefix.in
   fi
fi
}
#-------------------------------------------------------------------------------
# Creates a directory for old logs and inputs to be stored with a numerical tag from 1 to k
Sort ()
{
if [ ! -d "../logs_and_inputs" ]; then
    mkdir ../logs_and_inputs
    iter=1
else
   if [ -z "$(ls -A ../logs_and_inputs)" ]; then iter=1 else indices=() for entry in "../logs_and_inputs"/$prefix.in-*; do
         indices+=("${entry: -1}") done max=${indices[0]}
      for n in "${indices[@]}" ; do ((n > max)) && max=$n
      done
      iter=$((max+1)) fi fi max_iter=$((iter+max_runs))
}
#-------------------------------------------------------------------------------                                                                                                   
Automode () 
{
mpirun ~/path-to-pw.x < $prefix.in > $prefix.log
# Runs pw.x job, checks for completion and errors
if grep -E -q -- $errors "slurm.err"; then exit 1 fi if grep -q "job DONE." "$prefix.log"; then
   # Clear wavefunction files and temp directories
   rm -r *x*x*
   # Generates new input file
   python ~/path-to-in-gen.py $prefix.log $prefix.in $job # Tags and stores the previous input and log mv $prefix.in ../logs_and_inputs/$prefix.in-$iter
   mv $prefix.log ../logs_and_inputs/$prefix.log-$iter else exit 1 fi # Checks for generation of new input file if test -f "$prefix.in-new"; then
   mv $prefix.in-new $prefix.in
else
   exit 1
fi
let "iter=iter+1"
}
#-------------------------------------------------------------------------------                                                                                                   
Clear

Sort

while ((iter < max_iter)); do
   Automode
done

Odpowiedzi

4 l0b0 Sep 01 2020 at 10:02

Konkretne sugestie:

  1. Nazwy funkcji są zgodne z konwencją snake_case.
  2. Użyj More Quotes ™ .
  3. [[należy używać zamiast[ , ponieważ jest to bezpieczniejsze.
  4. [[ EXPRESSION ]] && [[ EXPRESSION ]]byłoby jaśniejsze niż [[ EXPRESSION && EXPRESSION ]], moim zdaniem.
  5. set -o errexit -o noclobber -o nounset -o pipefaili shopt -s globfailsprawiłoby, że obsługa błędów byłaby znacznie surowsza.
  6. Nie jest to już trywialny kod, więc poleciłbym zaimplementować go w języku innym niż powłoki, takim jak Python.

Sugestie dotyczące narzędzi:

  1. Bieganie shellcheckna skrypcie regularnie to dobry sposób, aby uchwycić ewentualne problemy. W tym przypadku jedyne, co znajdzie, to rm -r *x*x*:

    SC2035: Użyj ./ glob lub - glob, aby nazwy z myślnikami nie stały się opcjami.