我有以下bash脚本,该脚本提供Zentiy TUI来将数据插入数据库。
#!/bin/bash
tip_run1="$(zenity --entry --text "ENTER number of tip runs:" --entry-text "1")"
a=1
until
[[ $tip_run1 -lt $a ]]
do
input="$(zenity --forms --title="table tip_run" --text="Add a new tip run" --separator="," \
--add-entry="ENTER start_time, e.g. 8:20: " \
--add-entry="ENTER finish_time, e.g. 12:30: " \
--add-entry="ENTER weight in kg, -t numeric: "\
--add-entry="ENTER a note, -t text: ")"
psql -tA -U chh1 -d crewdb -c "SELECT SETVAL('tip_run_tip_runid_seq', (SELECT MAX(tip_runid) FROM tip_run), true);" >/dev/null 2>&1
startt="$(echo "$input" | awk -F, -v OFS=, '{print $1}')"
finisht="$(echo "$input" | awk -F, -v OFS=, '{print $2}')"
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="start_time and/or finish_time are incorrect" --text "Add a start_time and a finish_time" --separator="," \
--add-entry="WARNING! Something went wrong. Please enter a valid start_time, e.g. 8:20: " \
--add-entry="WARNING! Something went wrong. Please enter a valid 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 vart="$var2" 'BEGIN { FS="," } { print vart "," $3 "," $4 ; }' )"
input="$((IFS=, read -r b c d e ; echo "${b}ttt,${c}ttt,${d}xxx,${e}www" )<<<"$input")"
IFS=,; set -f; set --$input; out=
for i in "$@"; do
case "$i" in
xxx) var2="$(zenity --forms --title="weight field in table tip_run" --text "Add a weight in kg" --separator="," \
--add-entry="WARNING! You forgot to enter a weight. Please enter a valid weight, e.g. 12.5: ")"
until [[ ${var2} =~ ^[0-9]+([.][0-9]+)?$ ]] || [[ ${var2} = NULL ]]; do
var2="$(zenity --forms --title="weight field in table tip_run" --text "Add a weight in kg" --separator="," \
--add-entry="WARNING! You either forgot to enter a weight or didn't enter a number. Please enter a valid weight, e.g. 12.5: ")"
done
out="$out,${var2}"
;;
NULLxxx) out="$out,${i/%xxx/}";;
*xxx) if [[ "${i/%xxx}" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
out="$out,${i/%xxx/}"
else
until [[ ${var2} =~ ^[0-9]+([.][0-9]+)?$ ]] || [[ ${var2} = NULL ]]; do
var2="$(zenity --forms --title="weight field in table tip_run" --text "Add a weight in kg" --separator="," \
--add-entry="WARNING! You either forgot to enter a weight or didn't enter a number. Please enter a valid weight, e.g. 12.5: ")"
done
out="$out,${var2}"
fi
;;
*ttt) out="$out,'${i/%ttt/}:00'";;
#TRUEbool) out="$out,${i/%bool/}";;
#FALSEbool) out="$out,${i/%bool/}";;
#*bool) echo "empty input not allowed"; exit 0;;
NULLwww) out="$out,${i/%www/}";;
www) var2="$(zenity --forms --title="note field in table tip_run" --text "Add a note" --separator="," \
--add-entry="WARNING! You either forgot to enter a note. Please enter a note or NULL: ")"
until [[ ! ${var2} = "" ]]; do
var2="$(zenity --forms --title="note field in table tip_run" --text "Add a note" --separator="," \
--add-entry="WARNING! You either forgot to enter a note or to enter NULL. Please enter a note or NULL: ")"
done
if [[ ${var2} = "NULL" ]]; then
out="$out,${var2}"
else
out="$out,\$\$${var2}\$\$"
fi;;
*www) out="$out,\$\$${i/%www/}\$\$";;
esac;
done
#echo "${out:1}"
echo "" >> /tmp/crew.txt
echo "" >> /tmp/crew.txt
echo "-- INSERT INTO tip_run:" >> /tmp/crew.txt
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (${out:1});" >> /tmp/crew.txt
let a++
done
我知道脚本的各个组成部分都可以工作,但是当我运行它时,会收到以下错误消息:
./tip_run.txt: line 64: set: --: invalid option
set: usage: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
第64行位于以下位置:
62 input="$((IFS=, read -r b c d e ; echo "${b}ttt,${c}ttt,${d}xxx,${e}www" )< <<"$input")"
63
64 IFS=,; set -f; set --$input; out=
65 for i in "$@"; do
66
67 case "$i" in
我尝试过设置不同的选项,但似乎都没有用。有人可以让我走上正确的道路吗?
问题在于set --$input
,它应该是set -- $input
。也许它根本不应该在这里。
set -- $something
及其运作方式建议您不要使用以前的问题之一的答案set -- $OUTPUT
。完整的相关代码段如下:
IFS=,; set -f; set -- $OUTPUT
for i do …
注:for i do
,for i; do
并且for i in "$@"; do
是等价的。
在该问题中,您想使用,
定界符分割变量的内容。然后,您想遍历结果块。您尝试使用awk
。有人指出,shell可以做到这一点,而代码段就是这种方式。让我们分析一下它是如何工作的。
主要思想是利用这样一个事实,即未加引号的变量在扩展时会进行单词拆分。通常,不带引号的变量也会触发文件名的生成(例如,通配符的扩展,例如*
它们是否存储在变量中)。通常,您既不需要文件名生成,也不需要单词分割,因此通常的规则是始终双引号,除非您知道自己在做什么。在少数情况下,没有报价是合理的set -- $something
,但是您需要知道您在做什么。这是您在做什么:
IFS=,
以便将来的单词拆分被视为,
定界符;set -f
禁用文件名生成机制。此后,不带引号的$something
单词将安全地扩展为零个或多个单词。仍然您需要遍历它们。循环遍历位置参数很容易(即,您可以使用$1
,,$2
…;或$@
或或(不是同等的)$*
一次获取所有参数的参数;引号很重要)。
set
是内置的shell,可以设置或取消设置shell选项(例如set -f
我们已经知道的)和位置参数。看起来不像选项的参数会修改位置参数数组。例如,set foo bar
将$1
扩展到foo
并$2
扩展到bar
。
扩展中的单词$something
可以用分配给位置参数,set $something
但这在至少两个方面存在缺陷:
set
,它将被视为一个选项。该选项可能会或可能不会被识别为有效(受支持)选项。$something
扩展到正好为零的单词,则将set $something
以唯一set
形式结束,这不会修改位置参数的数组。第一个问题是一般性的,而不是特定于的set
。许多工具(包括set
)都支持双破折号(--
)来解决该问题。第二个问题特定于set
。该工具的设计也--
解决了第二个问题。我的意思是,如果$something
扩展到恰好为零的单词,set -- $something
则将结束,因为set --
这确实按预期修改了位置参数数组:所有位置参数都将未设置。
因此,set -- $something
从扩展$something
到位置参数分配零个或多个单词的一种有效方法,然后可以轻松地进行循环。
笔记:
可以跳过set -- $something
并开始这样的循环:
IFS=,; set -f
for i in $something; do
但是随后您进入修改为IFS
和的循环set -f
。使用set -- $something
,然后for i do
允许您先还原for
。在您当前的代码中,您似乎并不关心修改的IFS
和set -f
。通常,它们可以适得其反(您应该已经知道)。
在Bash中,您可以使用命名数组(例如,myarray
在此答案中)并在其上循环。
set --$something
或set --"$something"
?如果set --$something
(或set --"$something"
)--
与扩展为的第一个单词$something
(或扩展为的唯一单词)串联在一起"$something"
。有一些边缘情况可能会--
留下,--
但是最有可能留下--whatever
。该字符串以开头-
,因此看起来像一个或多个选项。
关于选项的约定很少。大多数工具都支持单破折号-单字符选项(短选项,例如-a
或-1
)。许多工具支持双破折号多字符选项(长选项,例如--almost-all
)。一些工具把单短线的多字符选项单选项(例如,在7z
有-bd
或-bt
),但许多将把-abc
一样-a -b -c
,如果没有-a
,也不-b
需要一个选项参数。通常,工具可以按其想要的任何方式解析和解释其参数,因此这可能很复杂。
set --whatever
不whatever
视为长选项,它根本不支持长选项。看起来set --whatever
几乎像set -- -w -h -a -t -e -v -e -r
,除非--
它不能像前面阐述的双破折号那样工作。此处--
尝试作为短选项,即单破折号-单字符选项,其中单字符部分碰巧是破折号。但是没有这么短的选择:
set: --: invalid option
--
需要是一个单独的参数。通过此后省略空间--
你做出set
错误地解释它的第一个参数选项。有趣的是,正确使用的 要点--
是表明选择权的终止。
set -- "$something"
吗?在一个(现在已删除)注释中,set -- "$something"
出现这个主意的原因可能是因为“总是引用”规则。这扩展$something
为一个单词。首先,主要目标是将单词分割成多个单词,因此引用绝对不是正确的选择。
假设有一段时间您确实想要$something
一个单词,但是您确实做到了set -- "$something"
,并且效果很好。在这种情况下,连续for i in "$@"; do
是没有意义的,因为您要遍历单个元素。不需要循环。
set
,for
和case
?在您已经提到的问题中,您使用相同的代码测试了每个字段。遍历字段是一个好主意。
在当前问题中:
$input
through的值,awk
我强烈怀疑,从设计的角度来看,此后恰好有四个逗号分隔的字段。IFS=, read -r
到拆分$input
到$b
,$c
,$d
和$e
; 这些是领域。${b}ttt,${c}ttt,${d}xxx,${e}www
再次完全保存。set -- $input
,所以不是$b
,$c
,$d
和$e
你有$1
,$2
,$3
和$4
。case
用于为不同的字段运行不同的代码。我的意思是NULLxxx
只能匹配第三个字段(${d}xxx
)。您过去一直xxx
在识别第三个字段,但是前面已经把它分开$d
了。为什么不测试$d
为是NULL
摆在首位?如果您事先不知道有多少个字段,则将其拆分为位置参数非常有用。如果您知道您刚好有四个,那么
IFS=, read -r b c d e
在主外壳中,将为您提供四个定义明确的单独变量以供使用。您仍然可以使用循环for i in "$b" "$c" "$d" "$e"; do
,但是由于仅在您的原始代码中${b}ttt
并且可以${c}ttt
共享一个大小写可以匹配(*ttt
)的情况,因此有意义的是循环遍历"$b"
和"$c"
,然后分别进行分析"$d"
和"$e"
。该代码常见的"$b"
和"$c"
是如此简单,你可以和重复它不引入一个循环:
out="$out,'$b:00'"
out="$out,'$c:00'"
然后:
# what to do if $d is empty
# what to do if $d is NULL
# what to do if $e is NULL
# what to do if $e is empty
# what to do if $e is valid
# etc.
如果您希望能够快速升级代码以支持需要验证的其他字段(例如已经支持的字段),则可以在其中标记不同的字段ttt
或xxx
在某种程度上有意义。是这样吗 即使这样,再次进行分裂,级联和分裂也似乎过于复杂。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句