테스트 조건이 작동하지 않는 Bash 스크립트 사례 설명

테스트 조건이 작동하지 않는 Bash 스크립트 사례 설명

다소 긴 스크립트(메인 스크립트)가 있습니다. 답변과 관련이 있을 수 있다고 생각하므로 여기에 모든 내용을 포함하겠습니다. 그러니 저를 미워하지 마세요. 이 스크립트의 모든 내용은 작동합니다. 내가 겪고 있는 유일한 문제는 본질적으로 동일한 끝 부분의 *www1) 및 *www2) 사례입니다. 이러한 경우에는 NULL 테스트가 작동하고 Zentiy 상자에 입력된 데이터가 올바르게 처리됩니다. 그러나 해당 Zenity 필드(invoice_number & note)에 아무것도 입력하지 않으면 else until [[ -n "${var2}" ]]; do...무시됩니다. 스크립트 끝에는 문제의 사례에 대해 더욱 단순화된 또 다른 스크립트를 포함했습니다(단순화). 실행해 보면 아무런 문제가 없으며 모든 것이 예상대로 작동합니다. 케이스는 원본에서 복사한 것이므로 하나는 작동하지만 다른 하나는 작동하지 않는 이유에 대해 머리를 뽑고 있습니다. 이 문제를 기꺼이 도와줄 사람이 있나요?

주요 스크립트:

#!/bin/bash


work_number="$(zenity --entry --text "ENTER number of work/job entries:" --entry-text "1")"
        a=1

until
        [[ $work_number -lt $a ]]
do

input="$(zenity --forms --title="table work" --text="Add a new job" --separator="," \
       --add-entry="ENTER clientid: " \
       --add-entry="ENTER job_start, -t time without time zone, e.g. '11:45:00', seconds allways zero: " \
       --add-entry="ENTER job_finish, -t time without time zone, e.g. '11:45:00', seconds allways zero: " \
       --add-entry="ENTER number_catchers, -t numeric, must be 0 if no waste has been collected or NULL if it has yet to be assigned to a tip run: " \
       --add-entry="ENTER mower_front, -t numeric:" \
       --add-entry="ENTER mower_back, -t numeric: " \
       --add-entry="ENTER categoryid: " \
       --add-entry="ENTER price, -t numeric: " \
       --add-entry="ENTER invoice_number, -t text: " \
       --add-entry="ENTER note, -t text: " \
       --add-entry="ENTER a tip_runid, -t integer: ")"

psql -tA -U chh1 -d crewdb -c "SELECT SETVAL('work_workid_seq', (SELECT MAX(workid) FROM work), true);" >/dev/null 2>&1
dlink="$(psql -tA -U chh1 -d crewdb -c "SELECT MAX(date_linkid) FROM date_link;")"

startt="$(echo "$input" | awk -F, -v  OFS=, '{print $2}')"
finisht="$(echo "$input" | awk -F, -v  OFS=, '{print $3}')"

st="$( date --date="$startt" +%s  2>/dev/null )"
ft="$( date --date="$finisht" +%s 2>/dev/null )"

if [ -n "$st" -a "$ft" ] ; then

    startt="$(date +%H:%M  -d "$startt"  )"
    finisht="$(date +%H:%M -d "$finisht" )"
    tzdiff="$(( ft - st ))"
else
    tzdiff=0
fi

while [[  ( ( ! "$startt"   =~ ^[0-1][0-9]:[0-5][0-9]$ ) && ( ! "$startt"  =~ ^[0-2][0-3]:[0-5][0-9]$ ) ) ||
          ( ( ! "$finisht"  =~ ^[0-1][0-9]:[0-5][0-9]$ ) && ( ! "$finisht" =~ ^[0-2][0-3]:[0-5][0-9]$ ) ) ||
          ( "$tzdiff" -le 0 )  ]];
do
    var2="$(zenity --forms --title="job start time and/or job finish time are incorrect" --text "Add a job start time and finish_time"  --separator="," \
                   --add-entry="WARNING! Something went wrong. Please enter a valid job start time, e.g. 8:20: " \
                   --add-entry="WARNING! Something went wrong. Please enter a valid job finish time, e.g. 12:30: ")"
    tzdiff=0

    if [ -n "$var2" ] ; then
       b1=$(echo "$var2" | cut -d, -f1 )
       b2=$(echo "$var2" | cut -d, -f2 )

       if [ -n "$b1" -a -n "$b2"  ] ; then
           tz1=$( date --date="$b1" +%s 2>/dev/null )
           tz2=$( date --date="$b2" +%s 2>/dev/null )

           if [ -n "$tz1" -a -n "$tz2" ] ; then
              startt=$(date +%H:%M -d "$b1" )
              finisht=$(date +%H:%M -d "$b2" )
              tzdiff=$(( tz2 - tz1 ))
           fi
       fi
    fi
done

var2="$startt,$finisht"

input="$( echo "$input" | awk -v vard="$dlink" -v vart="$var2" 'BEGIN {  FS="," } { print $1"xxx1" "," vard"ddd" "," vart "," $4"xxx2" "," $5"xxx3" "," $6"xxx4" "," $7"xxx5" "," $8"xxx6" "," $9"www1" "," $10"www2" "," $11"xxx7" ; }' )"

IFS=, read -ra array1 <<<"$input"
out=""

for i in "${array1[@]}"; do

        case "$i" in
        *ddd) out="$out,${i/%ddd/}";;
            
        *xxx1)  if [[ "${i/%xxx1/}" =~ ^[0-9]+$ ]]; then
                
                out="$out,${i/%xxx1/}"

                elif [[ "${i/%xxx1/}" = NULL ]]; then

                    out="$out,${i/%xxx1/}"

                else    until [[ ${var2} =~ ^[0-9]+$ ]] || [[ ${var2} = NULL ]]; do

                                        var2="$(zenity --forms --title="clientid field in table work" --text "Add a clientid"  --separator="," \
                                        --add-entry="WARNING! You either forgot to enter a clientid or didn't enter a number. Please enter a valid clientid: ")"

                                    done

                                    out="$out,${var2}"

                fi  
            
                ;;

        *xxx2) if [[ "${i/%xxx2/}" =~ ^[0-9]+([.][0-9]+)?$ ]]; then

                                out="$out,${i/%xxx2/}"

                                elif [[ "${i/%xxx2/}" = NULL ]]; then

                                        out="$out,${i/%xxx2/}"

                                else    until [[ ${var2} =~ ^[0-9]+([.][0-9]+)?$ ]] || [[ ${var2} = NULL ]]; do

                                        var2="$(zenity --forms --title="number of catchers field in table work" --text "Add number of catchers"  --separator="," \
                                        --add-entry="WARNING! You either forgot to enter number of catchers or didn't enter a number. Please enter a valid number of catchers: ")"

                                        done

                                        out="$out,${var2}"

                                fi

                                ;;

        *xxx3) if [[ "${i/%xxx3/}" =~ ^[0-9]+$ ]]; then

                                out="$out,${i/%xxx3/}"

                                elif [[ "${i/%xxx3/}" = NULL ]]; then

                                        out="$out,${i/%xxx3/}"

                                else    until [[ ${var2} =~ ^[0-9]+$ ]] || [[ ${var2} = NULL ]]; do

                                        var2="$(zenity --forms --title="front mower wheel hight field in table work" --text "Add front mower wheel hight"  --separator="," \
                                        --add-entry="WARNING! You either forgot to enter a front mower wheel hight or didn't enter a number. Please enter a valid front mower wheel hight: ")"

                                        done

                                        out="$out,${var2}"

                                fi

                                ;;

        *xxx4)  if [[ "${i/%xxx4/}" =~ ^[0-9]+$ ]]; then

                                out="$out,${i/%xxx4/}"

                                elif [[ "${i/%xxx4/}" = NULL ]]; then

                                        out="$out,${i/%xxx4/}"

                                else    until [[ ${var2} =~ ^[0-9]+$ ]] || [[ ${var2} = NULL ]]; do

                                        var2="$(zenity --forms --title="back mower wheel hight field in table work" --text "Add back mower wheel hight"  --separator="," \
                                        --add-entry="WARNING! You either forgot to enter a back mower wheel hight or didn't enter a number. Please enter a valid back mower wheel hight: ")"

                                        done

                                        out="$out,${var2}"

                                fi

                                ;;

        *xxx5)  if [[ "${i/%xxx5/}" =~ ^[0-9]+$ ]]; then

                                out="$out,${i/%xxx5/}"

                                elif [[ "${i/%xxx5/}" = NULL ]]; then

                                        out="$out,${i/%xxx5/}"

                                else    until [[ ${var2} =~ ^[0-9]+$ ]] || [[ ${var2} = NULL ]]; do

                                        var2="$(zenity --forms --title="categoryid field in table work" --text "Add a categoryid"  --separator="," \
                                        --add-entry="WARNING! You either forgot to enter a categoryid or didn't enter a number. Please enter a valid categoryid: ")"

                                        done

                                        out="$out,${var2}"

                                fi

                                ;;
            
        *xxx6)  if [[ "${i/%xxx6/}" =~ ^[0-9]+([.][0-9]+)?$ ]]; then

                                out="$out,${i/%xxx6/}"

                                elif [[ "${i/%xxx6/}" = NULL ]]; then

                                        out="$out,${i/%xxx6/}"

                                else    until [[ ${var2} =~ ^[0-9]+([.][0-9]+)?$ ]] || [[ ${var2} = NULL ]]; do

                                        var2="$(zenity --forms --title="price field in table work" --text "Add price"  --separator="," \
                                        --add-entry="WARNING! You either forgot to enter price or didn't enter a number. Please enter a valid price: ")"

                                        done

                                        out="$out,${var2}"

                                fi

                                ;;

        *xxx7)  if [[ "${i/%xxx7/}" =~ ^[0-9]+$ ]]; then

                                out="$out,${i/%xxx7/}"

                                elif [[ "${i/%xxx7/}" = NULL ]]; then

                                        out="$out,${i/%xxx7/}"

                                else    until [[ ${var2} =~ ^[0-9]+$ ]] || [[ ${var2} = NULL ]]; do

                                        var2="$(zenity --forms --title="tip_runid field in table work" --text "Add a tip_runid"  --separator="," \
                                        --add-entry="WARNING! You either forgot to enter a tip_runid or didn't enter a number. Please enter a valid tip_runid: ")"

                                        done

                                        out="$out,${var2}"

                                fi

                                ;;

        *ttt) out="$out,'${i/%ttt/}:00'";;

        *www1)  if [[ "${i/%www1/}" = NULL ]]; then

                out="$out,${i/%www1/}"

                elif [[ -n "${i/%www1/}" ]]; then

                    out="$out,\$\$${i/%www1/}\$\$"

                else    until [[ -n "${var2}" ]]; do

                    var2="$(zenity --forms --title="invoice number field in table work" --text "Add a invoice number"  --separator="," \
                                    --add-entry="WARNING! You either forgot to enter a invoice number. Please enter a invoice number or NULL: ")"

                    if [[ "${var2}" = NULL ]]; then

                        out="$out,${var2}"

                    else

                        out="$out,\$\$${var2}\$\$"

                    fi

                done

                fi
                                ;;

        *www2)  if [[ "${i/%www2/}" = NULL ]]; then

                                out="$out,${i/%www2/}"

                                elif [[ -n "${i/%www2/}" ]]; then

                                        out="$out,\$\$${i/%www2/}\$\$"

                                        else 

                                until [[ -n "${var2}" ]]; do

                                var2="$(zenityi --forms --title="note field in table work" --text "Add a note"  --separator="," \
                                --add-entry="WARNING! You either forgot to enter a note. Please enter a note or NULL: ")"

                                        if [[ "${var2}" = NULL ]]; then

                                                out="$out,${var2}"

                                        else

                                                out="$out,\$\$${var2}\$\$"

                                        fi

                done
                
                fi
                                ;;

        *) out="$out,'${i}:00'";;

esac;
done

echo "${out:1}"

let a++

done

단순화된 스크립트:

#!/bin/bash

work_number="$(zenity --entry --text "ENTER number of work/job entries:" --entry-text "1")"
        a=1

until
        [[ $work_number -lt $a ]]
do

input="$(zenity --forms --title="table work" --text="Add a new job" --separator="," \
       --add-entry="ENTER a: " \
       --add-entry="ENTER invoice reference field: " \
       --add-entry="ENTER b: ")"

input="$( echo "$input" | awk 'BEGIN {  FS="," } { print $1 "," $2"www1" "," $3 ; }' )"

IFS=, read -ra myarray <<<"$input"
out=""

for i in "${myarray[@]}"; do
        case "$i" in
        

        *www1) if [[ "${i/%www1/}" = NULL ]]; then

      out="$out,${i/%www1/}"

elif [[ -n "${i/%www1/}" ]]; then

      out="$out,\$\$${i/%www1/}\$\$"

else    until [[ -n "${var2}" ]]; do

            var2="$(zenity --forms --title="invoice number field in table work" --text "Add a invoice number"  --separator="," \
            --add-entry="WARNING! You either forgot to enter a invoice number. Please enter a invoice number or NULL: ")"

                    if [[ "${var2}" = NULL ]]; then

                         out="${var2}"

                    else

                         out="\$\$${var2}\$\$"

                    fi

        done

 fi
 ;;
 esac
done

out="${out#,}"
printf 'out=%s\n' "$out"
echo "$out"

let a++

done

답변1

설명

var2변수를 설정 해제하거나( unset var2) 빈 문자열을 할당하지 않고( ) 변수를 재사용하고 있습니다 var2=''. 그러므로 until [[ -n "${var2}" ]]; do …; done오래된 것을 사용합니다.비어 있지 않은값과 그 자리에 있는 코드는 실행되지 않습니다.

단순화된 스크립트에서는 var2에 처음 접근할 때 여전히 설정이 해제되어 있습니다 until [[ -n "${var2}" ]]; do. 이것이 차이점입니다.

글을 쓸 때마다 until [[ -n "${var2}" ]]; do(이전 루프에서 나온) 변수의 현재 값이 중요한지 스스로에게 물어보세요. 중요하지 않다면 중요하지 않게 만드세요. 직전에 변수를 설정 해제하세요 until.

대안은 코드를 함수로 구성하는 것입니다. Bash의 함수에서는 지역 변수를 정의할 수 있습니다. 지역 변수는 기본 스크립트나 이 함수 또는 다른 함수의 다른 호출 var2과 아무 관련이 없습니다 . 자세한 내용은 참조하세요 . 예를 들어, 함수를 생성 하고 정의 하면 다른(이전) 간섭의 위험 없이 함수에서 사용할 수 있습니다 .var2var2help localvalidate_invoice_numberlocal var2until [[ -n "${var2}" ]]; dovar2


다음 코드 조각은 에서 까지의 범위에서 두 개의 난수를 얻으려는 잘못된 시도 0입니다 9999. Bash에서는 $RANDOM다음 범위의 임의의 정수로 확장됩니다 . (우연히) 기대에 맞는 숫자를 얻을 때까지 Bash에서 임의의 숫자를 계속 쿼리할 것입니다 0. 32767이는 사용자에게 쿼리하는 접근 방식과 유사합니다. 원하는 범위에서 임의의 정수를 얻는 가장 빠른 방법은 아니지만 이 경우에도 근본적으로 결함이 있는 것은 아닙니다. 결함은 var2코드에서처럼 재사용에 있습니다. 무슨 일이 일어나는지 이해하는 데 도움이 되는 stderr에 대한 진단 메시지가 여기에 있습니다.

#!/bin/bash

for i in 1 2; do
   echo "Loop $i starts. var2 is ${var2:-empty or unset}." >&2
   until [ "$var2" -lt 10000 ] 2>/dev/null; do
      echo "Trying new random number." >&2
      var2="$RANDOM"
   done
   echo "Expectation met. Printing the result." >&2
   echo "$var2"
   echo "Loop $i ends. var2 is ${var2:-empty or unset}." >&2
done

코드를 실행하면 두 번째 루프가 새로운 난수를 전혀 얻지 못하는 것을 볼 수 있습니다. 이제 다음을 시도해 보겠습니다 unset.

#!/bin/bash

for i in 1 2; do
   echo "Loop $i starts. var2 is ${var2:-empty or unset}." >&2
   unset var2
   echo "Loop $i continues. var2 is ${var2:-empty or unset}." >&2
   until [ "$var2" -lt 10000 ] 2>/dev/null; do
      echo "Trying new random number." >&2
      var2="$RANDOM"
   done
   echo "Expectation met. Printing the result." >&2
   echo "$var2"
   echo "Loop $i ends. var2 is ${var2:-empty or unset}." >&2
done

local var2또 다른 접근 방식은 함수에서 사용하는 것입니다 .

#!/bin/bash

gimme_random () {
   local var2
   echo "Function starts. var2 inside is ${var2:-empty or unset}." >&2
   until [ "$var2" -lt 10000 ] 2>/dev/null; do
      echo "Trying new random number." >&2
      var2="$RANDOM"
   done
   echo "Expectation met. Printing the result." >&2
   echo "$var2"
   echo "Function ends. var2 inside is ${var2:-empty or unset}." >&2
}

for i in 1 2; do
   echo "Loop $i starts. var2 is ${var2:-empty or unset}." >&2
   gimme_random
   echo "Loop $i ends. var2 is ${var2:-empty or unset}." >&2
done

이것은 예상대로 작동합니다. 함수 내부의 변수는 함수 외부의 변수와 연결되지 않습니다. 함수가 다시 실행되면 새 인스턴스의 변수는 인스턴스에 로컬입니다.

없이 시도 local var2하면 첫 번째 (결함이 있는) 스니펫처럼 작동합니다. 이 경우 var2함수 외부와 내부(두 인스턴스 모두)는 동일합니다 var2.

또한 단일 셸에 순차적으로 붙여넣어 코드 조각을 실행하는 경우 var2(함수에서 로컬이 아닌 한) 한 코드 조각에서 다른 코드 조각으로 유지됩니다. 이것은 심지어 문제를 강조할 것입니다.

관련 정보