명령줄 옵션이 멈추고 변수의 기본값을 설정하지 않는 Bash 스크립트

명령줄 옵션이 멈추고 변수의 기본값을 설정하지 않는 Bash 스크립트

저는 bash 스크립팅을 처음 접했고 bash의 명령줄 기능도 완전히 처음 접했습니다. 사용자가 코드를 직접 편집하는 것을 선호하는 경우 명령줄 인수와 함께 작동하고 변수 값을 수동으로 설정하는 스크립트를 시도했습니다.

일반적인 아이디어는 다음과 같습니다.

  • 다양한 기능에 대한 명령줄 매개변수를 정의하려면 while/case/getopt 구조를 사용하세요.
  • 해당 케이스 내에서 각 옵션에 대한 변수 값을 설정합니다.
  • 나중에 if 조건을 사용하여 명령줄 인수가 실제로 제공되었는지 확인하세요.
  • 그렇지 않은 경우 해당 값이 기본 매개변수로 설정됩니다.

이런 방식으로 myscript.sh -i somestringif 문에서 -i와 관련된 변수를 사용하거나 수동으로 설정할 수 있습니다. 이렇게 하면 간단히 ./myscript.sh.

나는 내 코드의 if 상황이 실제로 아무것도 하지 않거나 적어도 내가 원하는 것을 하지 않는다는 것을 발견했습니다. 명령줄 인수 없이 스크립트를 실행한 다음 if 사례에서 설정해야 하는 기본값을 에코하면 해당 값이 비어 있습니다.

이는 해당 변수가 아직 아무 것도 설정되지 않았기 때문에 스크립트 뒷부분의 for 루프가 작동하지 않음을 의미합니다. 스크립트가 멈추는 줄은 다음과 같습니다. slurm_file_string=$(cat $slurm_template_file | sed "s/INPUT_FILE/$gs_file/")

그래서 나는 내가 달성하고 싶은 것을 달성하는 방법과 이 "막힌 문제"를 해결하는 방법을 모릅니다. if 상황 내부의 기본값이 실제로 어떤 일을 하도록 if 상황을 어떻게든 변경해야 하는데 어떻게 해야 할지 모르겠습니다.

이것은 내 코드입니다.

#!/bin/bash

# TODO: 
    # Need to figure out if I can launch all slurm jobs with "&" and let slurm handle the rest.
    # Add scratch removal logic to slurm file template. Makes more sense to do it per run in the file that actually runs gaussian.
    # Add commandline options for:
        # input folder (-i) 
        # verbose mode (-v)
        # extension name (-x)
        # slurm template name (-t)
    # Define function be_verbose() which wraps the logic for printing additional info if -v is set to true.

# INFO: Script for running a batch of gaussian jobs using the SLURM scheduler.
    # General program flow: 
        # The script finds all gaussian input files in inps_folder (needs to be manually specified)
            # The input files are identified by the file extension in "extension"
        # The script iterates over all gaussian input files.
            # For each file a slurm file is created based on the template: submit_gaussian_template.slurm
            # Inside the template the string "INPUT_FILE" is replaced by the current input file.
            # The new slurm file is copied to the input files folder
            # The script changes directories to the common pwd of the slurm file and gaussian input file
            # The slurm file is executed and then the next iteration starts.
                # The cleanup is handeled by the shell code inside the slurm file (deleting temp files from /scratch)
            
# IMPORTANT:
    # This script is designed for a certain folder structure.
    # It is required that all your gaussian input files are located in one directory.
    # That folder must be in the same dir as this script.
    # There must be a template slurm file in the directory of this script
    # There must be a string called INPUT_FILE inside the template slurm file 
################################################################################################################################################



# this implements command line functionality. If you do not wish to use them, look for MANUAL_VARS_SPEC below to specify your variables that way.
while getopts "i:vx:t:" opt; do
    case $opt in
        i)
            inps_folder="$OPTARG"
            ;;
            v)
            verbose=true
        ;;
        x)
        extension="$OPTARG"
        echo "$extension"
        ;;
        t)
        slurm_template_file="$OPTARG"
        ;;
        \?)
        echo "Usage: $0 [-i input_folder] [-s value_s] [-k value_k]"
        exit 1
        ;;
    esac
done


# MANUAL_VARS_SPEC: Change the varibles to the appropriate values if you do not wish to use the comman line options.
# These are essentially the default settings of the script.

# folder for input files
if [ -n "$inps_folder" ]; then # "if the commandline option is an empty string (not set), set the variable to this value."
    inps_folder="testinps"
fi

# verbose mode
if [ -n "$verbose" ]; then
    verbose=0
fi

# file extension of your gaussian input files
if [ -n "$extension" ]; then
    echo "AFASGSG"
    extension="gin"
fi

# slurm template file name
if [ -n "$slurm_template_file" ]; then
    slurm_template_file="submit_gaussian_template.slurm"
fi




# HELPER FUNCTIONS
function be_verbose(){
    local print_string="$1" # set the first argument provided to the funtion to the local var "print_string".
    if [ $verbose = true ]; then
        echo "$print_string"
    fi
}

echo "$inps_folder"
echo "$verbose"
echo "$extension"
echo "$slurm_template_file"


#### START OF MAIN LOOP.
files="${inps_folder}/*.${extension}" # iteratable for all gaussian input files.

for file in $files; do
    gs_file=$(basename $file) # get the file without the preceeding path
    gs_file_name="${gs_file%.*}" # get the file name without the extension
    
    # Make a new slurm file for the current job based on the template slurm file in the pwd.
    slurm_file_string=$(cat $slurm_template_file | sed "s/INPUT_FILE/$gs_file/") # get template and replace INPUT_FILE with gaussian input file. FAIL!!!!
    slurm_file="${gs_file_name}.slurm"
    echo "$slurm_file_string" > "$slurm_file" # write the string of the new slurm file to a new file
    mv "$slurm_file" "${inps_folder}/${slurm_file}" # move the new slurm file to the inps_folder

    cd "$inps_folder" # change directories so that slurm files can be executed
    echo "Is running ${gs_file}" #PUT HERE WHATEVER THE COMMAND FOR RUNNIGN A SLURM FILE IS &
    cd ..
done

어떤 의견이라도 미리 감사드립니다.

답변1

일반적으로 문제를 입증하기에 충분한 "검증 가능한 최소한의 코드 예제"가 있으면 도움을 주기가 더 쉽습니다. 그러나 여기서 나는 문제를 볼 수 있다고 생각합니다.

옵션을 구문 분석할 때 다음과 같은 코드가 있습니다.

while getopts 't:' opt
do
    case "$opt" in
        (t) slurm_template_file="$OPTARG" ;;
    esac
done

하지만 나중에 보면 '변수에 값이 있으면 고정된 값으로 설정합니다.":

if [ -n "$slurm_template_file" ]
then
    slurm_template_file='submit_gaussian_template.slurm'
fi

변수가 설정되지 않았거나 비어 있는 경우 기본값을 할당하는 -z대신 이 코드를 사용하고 싶었습니다 .-n

내 접근 방식은 변수를 기본값으로 설정한 다음 명령줄 스위치를 사용하여 이를 재정의하는 것이었습니다. 또한 나중에 결정을 내리기 위해 필요한 경우 사용자에게 명시적으로 값을 설정하도록 지시하는 플래그를 설정할 수도 있지만, 내 경험상 이는 일반적으로 필요하지 않습니다.

slurm_template_file='submit_gaussian_template.slurm'
slurm_template_file_isset=false

while getopts 't:' opt
do
    case "$opt" in
        (t)
            slurm_template_file="$OPTARG"
            slurm_template_file_isset=true
            ;;
    esac
done

if "$slurm_template_file_isset"
then
    echo "User overrode the default" >&2
fi
echo "The working value is: $slurm_template_file" >&2

또는 코드 상단에 기본값을 설정하고 작업 값이 설정되지 않은 경우 사용할 수 있습니다. 코드는 변수 이름이 길기 때문에 약간 투박하지만 주의해서 보면 더 명확해질 수 있습니다.

template_default='submit_gaussian_template.slurm'
template=

while getopts 't:' opt
do
    case "$opt" in
        (t)
            template="$OPTARG"
            ;;
    esac
done

if [ -n "$template" ]
then
    echo "User overrode the default: $template" >&2
fi
echo "The working value is: ${template:-$template_default}" >&2

관련 정보