
我有一個有點長的腳本(主腳本)。我將把它全部包含在這裡,因為我相信它可能與答案有關,所以請不要討厭我。該腳本中的所有內容都有效。我唯一遇到的問題是接近末尾的情況 *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
使用一些舊的非空value 和代替的程式碼…
永遠不會被執行。
在簡化的腳本中,var2
當您第一次訪問時仍未設定until [[ -n "${var2}" ]]; do
。這就是差別。
每次編寫時until [[ -n "${var2}" ]]; do
問自己變數的當前值(來自上一個循環左右)是否重要。如果它不重要,那就讓它變得不重要:取消設定之前的變數until
。
另一種方法是在函數中組織程式碼。在 Bash 的函數中,您可以定義局部變數。局部變數與主腳本中的(如果有的話)或與此或另一個函數的另一個呼叫var2
無關。詳情請參閱。例如,如果您建立函數並在其中定義,那麼您將能夠在該函數中使用,而不會受到其他(舊)幹擾的風險。var2
var2
help local
validate_invoice_number
local var2
until [[ -n "${var2}" ]]; do
var2
例子
下面的程式碼是一個有缺陷的嘗試,從 到0
的範圍內取得兩個隨機數9999
。在 Bash 中,擴展為從到$RANDOM
範圍內的隨機整數我們將繼續在 Bash 中查詢隨機數,直到(偶然)我們得到一個滿足我們期望的隨機數。這與查詢用戶的方法類似。它不是從所需範圍內獲取隨機整數的最快方法,但在這種情況下它也沒有根本性的缺陷。該缺陷在於重複使用,就像在您的程式碼中一樣。發送至 stderr 的診斷訊息可協助您了解發生的情況。0
32767
var2
#!/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
。
另請注意,如果您透過將片段按順序貼到單一 shell 中來運行片段,那麼var2
(除非函數中是本地的)將從一個片段保留到另一個片段。這甚至會強調問題。