3

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
4

2 に答える 2

3

問題は、算術式内で文字列比較を実行しようとしていることです。複合式に切り替えます。

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

または、 の正しい要素にアクセスしていることを確認してくださいmsgData

于 2013-07-08T12:38:40.793 に答える
2

これは、bash での連想配列の実装の制限であると最初に思われました (v4.3.11 以降)。

ドキュメントには次のように記載されています。

連想配列は次を使用して作成されます

declare -A name.

配列は、次の形式の複合割り当てを使用して割り当てられます

name=(value1 value2 … )

ここで、各値は[subscript]=stringの形式です。

そして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}を使用しているため、整数コンテキストで評価される可能性があります。<

したがって、最初にそのコンテキストをエスケープするために quote it のようなことをしたいと思うでしょう。

または、修飾子を使用せずに省略形を少なくして単純に実行します。これ:-は、その行の他のすべての句読点と組み合わせると、実際に行のノイズの印象に寄与します. 例えば:

msgTime=${msgData[$email]}
test -n "$msgTime" || msgTime=0
if [ $msgTime -lt $(LC_TIME=C date -d yesterday +%s) ]; then
于 2016-04-05T09:41:22.177 に答える