
Ich habe ein ziemlich langes Skript (Hauptskript). Ich werde es hier vollständig einfügen, da ich glaube, dass es für die Antwort relevant sein könnte, also seien Sie bitte nicht so ekelhaft. Alles in diesem Skript funktioniert. Das einzige, womit ich Probleme habe, sind die Fälle *www1) und *www2) am Ende, die im Wesentlichen gleich sind. Der NULL-Test funktioniert und die in die Zenity-Felder eingegebenen Daten werden für diese Fälle korrekt verarbeitet. Wenn ich jedoch nichts in die entsprechenden Zenity-Felder eingebe (Rechnungsnummer und Notiz), else until [[ -n "${var2}" ]]; do...
wird dies ignoriert. Am Ende des Skripts habe ich ein weiteres, vereinfachtes Skript nur für den betreffenden Fall eingefügt (vereinfacht). Wenn ich es ausführe, gibt es kein Problem und alles funktioniert wie erwartet. Der Fall ist einfach vom Original kopiert, also reißt es mich die Haare aus, warum das eine funktioniert, das andere aber nicht. Ist jemand bereit, dabei zu helfen?
Das Hauptskript:
#!/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
Vereinfachtes Skript:
#!/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
Antwort1
Erläuterung
Sie verwenden die var2
Variable erneut, ohne sie zu löschen ( unset var2
) oder ihr einen leeren String zuzuweisen ( var2=''
). Daher until [[ -n "${var2}" ]]; do …; done
werden einige altenicht leerWert und der Code anstelle von …
wird nie ausgeführt.
Im vereinfachten Skript var2
ist noch nicht festgelegt, wenn Sie zum ersten Mal zu gelangen until [[ -n "${var2}" ]]; do
. Das ist der Unterschied.
Fragen Sie sich jedes Mal, wenn Sie schreiben, until [[ -n "${var2}" ]]; do
ob der aktuelle Wert der Variablen (aus der vorherigen Schleife oder so) wichtig sein sollte. Wenn er keine Rolle spielen sollte, sorgen Sie dafür, dass er keine Rolle spielt: Setzen Sie die Variable direkt vor zurück until
.
Eine Alternative besteht darin, Ihren Code in Funktionen zu organisieren. In einer Funktion in Bash können Sie lokale Variablen definieren. Lokale var2
Variablen haben nichts mit var2
dem Hauptskript (falls vorhanden) oder mit var2
einem anderen Aufruf dieser oder einer anderen Funktion zu tun. help local
Weitere Einzelheiten finden Sie unter. Wenn Sie beispielsweise eine Funktion erstellen validate_invoice_number
und local var2
darin definieren, können Sie sie until [[ -n "${var2}" ]]; do
in der Funktion verwenden, ohne dass das Risiko besteht, dass eine andere (alte) Funktion var2
dazwischenfunkt.
Beispiel
Der folgende Codeabschnitt ist ein fehlerhafter Versuch, zwei Zufallszahlen aus einem Bereich von 0
bis zu erhalten 9999
. In Bash $RANDOM
wird zu einer zufälligen Ganzzahl aus einem Bereich von bis erweitert 0
. 32767
Wir werden Bash so lange nach Zufallszahlen abfragen, bis wir (zufällig) eine erhalten, die unseren Erwartungen entspricht. Dies ähnelt Ihrem Ansatz, bei dem Sie den Benutzer abfragen. Dies ist nicht die schnellste Methode, um eine zufällige Ganzzahl aus dem gewünschten Bereich zu erhalten, aber in diesem Fall ist sie auch nicht grundsätzlich fehlerhaft. Der Fehler liegt in der Wiederverwendung var2
, wie in Ihrem Code. Diagnosemeldungen an stderr helfen Ihnen zu verstehen, was passiert.
#!/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
Führen Sie den Code aus und Sie werden sehen, dass die zweite Schleife überhaupt keine neue Zufallszahl erzeugt. Versuchen wir es jetzt mit 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
Ein anderer Ansatz besteht darin , in einer Funktion Folgendes zu verwenden :
#!/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
Dies funktioniert wie erwartet. Die Variable innerhalb der Funktion hat keine Verbindung zur Variable außerhalb der Funktion. Wenn die Funktion erneut ausgeführt wird, ist die Variable in der neuen Instanz lokal für die Instanz.
Versuchen Sie es ohne local var2
und es wird sich wie der erste (fehlerhafte) Ausschnitt verhalten. In diesem Fall var2
ist es außerhalb und innerhalb der Funktion (beide Instanzen) gleich var2
.
Beachten Sie auch, dass, wenn Sie die Snippets ausführen, indem Sie sie einfach nacheinander in eine einzelne Shell einfügen, var2
(sofern sie nicht lokal in der Funktion sind) von einem Snippet zum anderen übergegangen wird. Dies wird das Problem noch verschärfen.