我写这个脚本:
for ip in ${ARRAY[*]}; do
for e in ${ARRAY[*]}; do
echo $e
done | grep -c "$ip" | if [[ "$(cat)" -lt "10" && $sent != *"$ip"* ]]; then
sent=$sent$ip
sed -n "/$ip/p" $1 | mail -s "subject" "mail@mail.mail"
fi
done
我想从ARRAY
获取每个元素,并计算此项目在ARRAY
中的时间。如果此计数小于10并且此元素是第一次计算(为避免计算元素两次),则会发送一封电子邮件。
但是,sent
变量不保存字符串连接。如果我在赋值后立即生成echo $ sent
,则发送返回预期结果。
如果我在echo $ sent
后面fi
,则该变量已为空。显然,通过这种方式,两个元素正在考虑并且发送两封邮件而不是一封。
我做错了什么?
答案 0 :(得分:1)
您的尝试在语法和效率方面存在许多问题。尝试使用http://shellcheck.net/进行即时修复(不正确的引用等),但你真的应该重构像
这样的东西printf '%s\n' "${ARRAY[@]}" |
sort | uniq -c | sort -rn |
while read -r count ip; do
case $count in [1-9]) break;; esac # stop looping after 10
sed -n "/$ip/p" "$1" | mail -s "subject" "mail@mail.mail"
done
对于任何有意义的存储在Bash数组中的任何事情,排序的开销应该可以忽略不计(尽管将它放在数组中可能实际上是你的基本错误)并且显着简化了脚本的其余部分。这样,您就可以避免跟踪下游代码中的重复项,并避免多次循环遍历相同的值和文件。
答案 1 :(得分:0)
这与" Bash variable scope"相同:您正在进入if
语句,这会创建一个子shell。子shell有一个新的作用域,在if语句完成后会丢失。
在众多解决方案中,您可以echo
每次更新sent
和tail -n1
最后的整个语句,只显示sent
的最后一个版本:< / p>
for ip in "${ARRAY[@]}"; do
for e in "${ARRAY[@]}"; do
echo "$e"
done | grep -c "$ip" | if [[ "$(cat)" -lt "10" && $sent != *"$ip"* ]]; then
sent=$sent$ip
sed -n "/$ip/p" "$1" | mail -s "subject" "mail@mail.mail"
echo "$sent"
fi
done | tail -n1