Declaración de caso de script Bash que incluye condiciones de prueba que no se comportan

Declaración de caso de script Bash que incluye condiciones de prueba que no se comportan

Tengo un guión algo largo (guión principal). Lo incluiré todo aquí porque creo que puede ser relevante para la respuesta, así que no me odien. Todo en este script funciona. Lo único con lo que estoy luchando es con los casos *www1) y *www2) cerca del final, que son esencialmente iguales. La prueba NULL funciona y los datos que se ingresan en los cuadros de Zentiy se manejan correctamente para estos casos. Sin embargo, si no ingreso nada en los campos correspondientes de Zenity (número_factura y nota), else until [[ -n "${var2}" ]]; do...se ignora. Al final del guión he incluido otro guión más simplificado justo para el caso en cuestión (simplificado). Cuando lo ejecuto no hay ningún problema y todo funciona como se esperaba. El caso acaba de ser copiado del original, así que me estoy arrancando los pelos de por qué uno funciona pero no el otro. ¿Alguien está dispuesto a ayudar en esto?

El guión principal:

#!/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

Guión simplificado:

#!/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

Respuesta1

Explicación

Estás reutilizando la var2variable sin desarmarla ( unset var2) ni asignarle una cadena vacía ( var2=''). Por lo tanto until [[ -n "${var2}" ]]; do …; doneutiliza algunos viejosno vacíovalue y el código en lugar de nunca se ejecuta.

En el script simplificado var2todavía no está configurado cuando accedes por primera vez until [[ -n "${var2}" ]]; do. Ésta es la diferencia.

Cada vez que escriba, until [[ -n "${var2}" ]]; dopregúntese si el valor actual de la variable (del ciclo anterior) debería importar. Si no debería importar, entonces haga que no importe: desactive la variable justo antes until.

Una alternativa es organizar su código en funciones. En una función en Bash puedes definir variables locales. La variable local var2no tendría nada que ver var2(si la tuviera) con el script principal o con var2otra invocación de esta u otra función. Ver help localpara más detalles. Por ejemplo, si crea una función validate_invoice_numbery local var2la define, podrá utilizarla until [[ -n "${var2}" ]]; dosin ningún riesgo de que otra (antigua) var2interfiera.


Ejemplo

El siguiente fragmento de código es un intento fallido de obtener dos números aleatorios en un rango de 0hasta 9999. En Bash $RANDOMse expande a un entero aleatorio desde un rango de 0hasta 32767Seguiremos consultando a Bash números aleatorios hasta que (por casualidad) obtengamos uno que cumpla con nuestras expectativas. Esto es similar a su enfoque en el que consulta al usuario. No es el método más rápido para obtener un número entero aleatorio del rango deseado, pero en este caso tampoco es fundamentalmente defectuoso. La falla está en la reutilización var2, como en su código. Los mensajes de diagnóstico para stderr están aquí para ayudarlo a comprender lo que sucede.

#!/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

Ejecute el código y verá que el segundo bucle no obtiene ningún número aleatorio nuevo. Ahora probemos con 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

Otro enfoque es utilizar local var2en una función:

#!/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

Esto funciona como se esperaba. La variable dentro de la función no tiene conexión con la variable fuera de la función. Cuando la función se ejecuta nuevamente, la variable en la nueva instancia es local a la instancia.

Pruébelo sin él local var2y se comportará como el primer fragmento (defectuoso). En este caso, var2el exterior y el interior de la función (ambas instancias) son iguales var2.

También tenga en cuenta que si ejecuta los fragmentos simplemente pegándolos secuencialmente en un solo shell, entonces var2(a menos que sea local en la función) permanecerán de un fragmento a otro. Esto incluso enfatizará el problema.

información relacionada