2017-03-01 91 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