
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 var2
variable sin desarmarla ( unset var2
) ni asignarle una cadena vacía ( var2=''
). Por lo tanto until [[ -n "${var2}" ]]; do …; done
utiliza algunos viejosno vacíovalue y el código en lugar de …
nunca se ejecuta.
En el script simplificado var2
todavía no está configurado cuando accedes por primera vez until [[ -n "${var2}" ]]; do
. Ésta es la diferencia.
Cada vez que escriba, until [[ -n "${var2}" ]]; do
pregú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 var2
no tendría nada que ver var2
(si la tuviera) con el script principal o con var2
otra invocación de esta u otra función. Ver help local
para más detalles. Por ejemplo, si crea una función validate_invoice_number
y local var2
la define, podrá utilizarla until [[ -n "${var2}" ]]; do
sin ningún riesgo de que otra (antigua) var2
interfiera.
Ejemplo
El siguiente fragmento de código es un intento fallido de obtener dos números aleatorios en un rango de 0
hasta 9999
. En Bash $RANDOM
se expande a un entero aleatorio desde un rango de 0
hasta 32767
Seguiremos 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 var2
en 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 var2
y se comportará como el primer fragmento (defectuoso). En este caso, var2
el 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.