2017-03-01 92 views
1

我试图编写一个脚本来验证指标的所有统计信息都是正面的,然后再使用该服务进行任何更改。我被困在该部分在思考着如何尾巴以下用例的递归:Bash中的尾递归

function load_cache() { 
    cacheStat=($(curl -s -X GET "http://localhost:${MET_PORT}/metrics" | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="cacheSize" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "cacheSize" | cut -d ':' -f 2)) 

    # the above gives me the ouput(cacheStat) as - 
    # 2.0 
    # 311.0 
    # 102.0 

    count=0 
    for index in ${!cacheStat[*]} 
    do 
     if [[ ${cacheStat[$index]} -le 0 ] && [ $count -lt 3 ]]; then 
      sleep .5 
      count=$[$count +1]; 
      load_cache 
      #Wouldn't the above initialise `count` to 0 again. 
     fi 
    done 
} 

我所试图做的是,如果任何在cacheStat的元素小于或等于0,然后睡眠.5秒,然后再次查询cacheStat并再次检查其所有元素。虽然不是这样做超过3倍,我正在尝试使用`count。

对任何改进脚本的建议均可使用。


更新 - 在修改剧本由@Inian作为建议

RETRY_COUNT=0 
function load_cache() { 
    cacheStat=($(curl -s -X GET "http://localhost:${MET_PORT}/metrics" | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="cacheSize" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "cacheSize" | cut -d ':' -f 2)); 
    for index in ${!cacheStat[*]} 
    do 
     echo "Stat - ${cacheStat[$index]}" 
     if ((${cacheStat[$index]} <= 0)) && (($RETRY_COUNT < 3)); then 
      echo "Attempt count - ${RETRY_COUNT}" 
      sleep .5s 
      RETRY_COUNT=$((RETRY_COUNT +1)); 
      load_cache 
     fi 
    done 
} 

日志阅读 -

>  > + cacheStat=($(curl -s -X GET "http://localhost:${MET_PORT}/metrics" | sed 's/\\\\\//\//g' | sed 
> 's/[{}]//g' | awk -v k="cacheSize" 
>  > '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 
>  > 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w 
>  > "cacheSize" | cut -d ':' -f 2)) 
>  > ++ curl -s -X GET http://localhost:8181/metrics 
>  > ++ sed 's/\\\\\//\//g' 
>  > ++ sed 's/[{}]//g' 
>  > ++ sed 's/[\,]/ /g' 
>  > ++ awk -v k=cacheSize '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' 
>  > ++ sed 's/\"\:\"/\|/g' 
>  > ++ cut -d : -f 2 
>  > ++ sed 's/\"//g' 
>  > ++ grep -w cacheSize 

,它甚至没有重复我猜。

+0

你的脚本有一些语法问题。修复它之前尝试回来,你确定这工作? – Inian

+0

@Inian它没有。这就是分享它的原因。请你指出缺陷。考虑一下我是一个新手bash。试图执行脚本,我只能看到直到'count = 0',并且没有任何提示。即使我在那里放了一个“回声”。 – nullpointer

+1

请参考下面的答案,首先通过在函数外移动count来移除无限递归。 – Inian

回答

2

通过将count=0移到函数体外部来消除无限递归。

而且你的脚本几个问题,一个语法错误和过时结构,线12-14应该是,

if [[ ${cacheStat[$index]} -le 0 ]] && [[ $count -lt 3 ]]; then 
    sleep .5s 
    count=$((count +1)); 
    load_cache 
fi 

或)使用一个更可读的算术运算符,(())if-clause作为

if ((${cacheStat[$index]} <= 0)) && (($count < 3)); then 

bash does not inherently support floating point arithmetic (comparison in your case), use a third party tool like bc , awk for this,

if (($(echo "${cacheStat[$index]} <= 0" | bc -l))) && (($count < 3)); then 
+0

此外,比较当前给出的输出为'语法错误:无效算术运算符(错误标记为“.0 <= 0.0”)'。由于我们的输入变成了'2.0' – nullpointer

+0

,所以你不能比较'bash'中的浮点值。不为你工作,并不意味着答案是不正确的,通过不接受它。 – Inian

+0

嗯,我明白了。我想我会将它转换为int。谢谢。 – nullpointer

1

你能避免所有的ad-hoc JSON使用JSON解析器进行解析。

# Avoid using Bash-only "function" keyword 
load_cache() { 
    local try 
    for try in 1 2 3; do 
     # Suction: jq doesn't return non-zero exit code for no match 
     # work around that by piping to grep . 
     if curl -s -X GET "http://localhost:${MET_PORT}/metrics" | 
      jq '.[] | select(cacheSize < 0)' | 
      grep . 
     then 
      # Notice also redirection to stderr for diagnostic messages 
      echo "$0: Attempt $try failed, sleeping before retrying" >&2 
      sleep 0.5 
     else 
      # Return with success, we are done, exit function 
      return 0 
     fi 
    done 

    # Return failure 
    return 1 
} 

我看不出有任何理由,更喜欢递归在一个简单的循环for控制重试次数。

如果您从不想看到违规值,则可以在条件中使用grep -q。如果你不想输出,我期待你会做load_cache >/dev/null

如果您想查看非违规值,代码将需要一些重构,但我的重点是优化和简洁地完成中心工作。这里有一个草图,主要是为了向你展示jq的语法。

load_cache() { 
    local try 
    local results 
    for try in 1 2 3; do 
     results=$(curl -s -X GET "http://localhost:${MET_PORT}/metrics" | 
      jq '.[] | .cacheSize' | tr '\n' ' ') 
     echo "$0: try $try: cacheSize $results" >&2 
     # Funky: massage the expression we test againt into a normalized form 
     # so that we know that the value will always be preceded by a space 
     case " $results " in 
      *" 0 "* | *" -"*) 
      case $try in 
       3) echo "$0: try $try failed; aborting" >&2 ;; 
       *) echo "$0: try $try failed; sleeping before retrying" >&2 
       sleep 0.5 ;; 
      esac;; 
      *) return 0 
     esac 
    done 
    return 1 
} 

嵌套case避免在最后一次迭代睡觉是不是特别优雅,但至少应确保读者是清醒的。/-8