bash 语法错误:具有令牌"@mail.com"的算术运算符无效



我有一个执行SQL SELECT并使用输出发送一些电子邮件的脚本,但该脚本存在问题,导致错误消息:

第34行:johne@mail.com:语法错误:算术运算符无效(错误标记为"@mail.com")

第34行是:

if (( ${msgData[$email]:-0} < $(LC_TIME=C date -d yesterday +%s) )); then

这是脚本:

#!/bin/bash
${BASH_VERSION+shopt -s extglob lastpipe} 2>/dev/null
# Full path to a file to store our date offset data. Will be overwritten.
datefile=date.log
# Assign your vars or insert whatever code does so here.
user=user pass=pass db=db
function doit {
    typeset x
    for x; do
        if [[ -z $x ]]; then
            echo 'doit: missing an argument.' >&2
            return 1
        fi
    done
    typeset template=$(</dev/fd/4)
    exec 4<&-
    sqlplus "${1}/${2}@${3}" <&3 | {
        if [[ -f $datefile ]]; then
            . "$datefile" || return 1
        else
            # An associative array that maps from num -> timestamp
            typeset -A msgData
        fi
        # If we've successfully read the file containing timestamps, then overwrite with new data on RETURN
        ${msgData+trap 'trap RETURN; typeset -p msgData >"$datefile"' RETURN}
        while IFS=, read -r num email limit orders; do
            ${email:+:} continue
            if (( ${msgData[$email]:-0} < $(LC_TIME=C date -d yesterday +%s) )); then
                printf -- "$template" "email" "$num" "$limit" "$orders" |
                    /usr/sbin/sendmail -f sender@example.com -oi -t
                msgData[$email]=$(LC_TIME=C date +%s)
            else
                printf 'Mail already sent to %s within the last 24 hours... skipping.n' "$email" >&2
            fi
        done
    }
} 5<&0 <<SQL 3<&0 <<TEMPLATE 4<&0 <&5-
set pagesize 0
set feedback 0
SELECT kred_lim.kunr ||','|| kust_adr.ku_email ||','|| kred_lim.kred_limit ||','|| kred_lim.kred_zu_zahlen
FROM kred_lim, kust_adr
WHERE kred_lim.kred_zu_zahlen > kred_lim.kred_limit
AND kred_lim.kunr = kust_adr.ku_nr;
SQL
Subject: Credit limit
To: %s
Customer number: %s
Credit limit: %s
Current orders: %s
TEMPLATE
if ! doit "$user" "$pass" "$db"; then
    echo 'we failed :(' >&2
    exit 1
fi

问题是您试图在算术表达式中执行字符串比较。切换到复合表达式:

if [[ ${msgData[$email]:-0} < $(LC_TIME=C date -d yesterday +%s) ]]; then

或者检查您是否正在访问msgData的正确元素。

在我看来,这首先是对bash中关联数组实现的限制(从这里的v4.3.11开始)。

文件上写着:

使用创建关联阵列

declare -A name.

数组使用形式的复合赋值进行赋值

name=(value1 value2 … )

其中每个值的形式为[subscript]=字符串

然后你可以查找几行前面的subscript

下标被视为必须计算为数字的算术表达式。

所以它在说一个字符串"foo@bar"不能计算为数字,也不能用作数组键?但这并不能解释为什么没有"@"可以

令人困惑的是,当你手动完成任务时,例如

declare -A emails_to_accounts=( 
    ["foo@bar.com"]="baz" 
    ["qux@bar.com"]="quux" 
)
for email in "${!emails_to_accounts[@]}"; do
    name=${emails_to_accounts[${email}]}
    : [...whatever...]
done

这很好。打扰

事实证明,解决方案是重复分配中的declare -A部分,如下所示:

declare -A "hash_name+=([$email]=$whatever)"

在上面的特定示例中,${msgData[$email]:-0}很可能是在整数上下文中求值的,因为您使用了<比较。

所以我敢打赌,你想先引用它来逃避上下文。

或者简单地用更少的短手,不使用:-修饰符,当与该行上的所有其他标点符号组合时,这确实会给人留下行噪声的印象。例如:

msgTime=${msgData[$email]}
test -n "$msgTime" || msgTime=0
if [ $msgTime -lt $(LC_TIME=C date -d yesterday +%s) ]; then

相关内容

最新更新