2017-03-01 8 views
1

Ich habe versucht, ein Skript zu schreiben, um zu überprüfen, dass alle Statistiken einer Metriken positiv sind, bevor ich weitere Änderungen mit dem Dienst vornehmen. Der Teil I an bin stecken denkt über, wie man Schwanz die Rekursion für den folgenden Anwendungsfall:Tail Rekursion in 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 
} 

Was ich versuche zu tun ist, wenn eine der Elemente in den cacheStat kleiner oder gleich 0, dann schlafen für .5 Sekunden und Abfrage der CacheStat erneut und führen Sie die Überprüfung für alle seine Elemente erneut. Obwohl nicht mehr als 3 Mal, für die ich versuche zu zählen.

Offen für jeden Vorschlag, um das Skript zu verbessern.


aktualisieren - Auf die Skripte modifizieren, wie durch @Inian vorgeschlagen

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 
} 

Die Protokolle lesen -

>  > + 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 

Es ist nicht einmal iterieren Ich denke, .

+0

Ihr Skript hat einige Syntaxprobleme. Repariere es, bevor du es zurückprobierst. Bist du sicher, dass das funktioniert hat? – Inian

+0

@Inian Es hat nicht. Deshalb teilen Sie es. Und könnten Sie bitte auf die Fehler hinweisen? Betrachten Sie mich als Neuling, um zu bash.Wenn ich versuche, das Skript auszuführen, sehe ich nur "count = 0" und nichts voraus. Auch wenn ich da ein "Echo" setze. – nullpointer

+1

Verweisen Sie meine Antwort unten, entfernen Sie in erster Linie unendliche Rekursion, indem Sie 'count' außerhalb der Funktion bewegen. – Inian

Antwort

2

Entfernen Sie die unendliche Rekursion, indem Sie die count=0 außerhalb des Funktionskörpers verschieben.

Auch Ihr Skript hat einige Probleme, eine Syntax Verletzung und ein veralteten Konstrukt, Linien 12-14 habe sein sollen,

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

oder) verwenden, um einen besser lesbaren arithmetischen Operator, (()) im if-clause als

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

Auch gibt der Vergleich derzeit eine Ausgabe als Syntaxfehler: ungültiger arithmetischer Operator (Fehler Token ist ".0 <= 0.0") '. Da unsere Eingabe "2.0" – nullpointer

+0

wird, können Sie float-Werte in 'bash' nicht vergleichen. Nicht für dich arbeiten, bedeutet nicht, die Antwort ist nicht richtig, indem Sie es nicht akzeptieren. – Inian

+0

hmmm, ich verstehe. Ich denke ich würde es dann in int umwandeln. Vielen Dank. – nullpointer

1

können Sie vermeiden alles, was ad-hoc-JSON Analyse mit einem JSON-Parser.

# 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 
} 

Ich sehe keinen Grund zur Steuerung der Anzahl der Wiederholungen Rekursion über eine einfache for Schleife bevorzugen.

Wenn Sie die fehlerhaften Werte nicht sehen möchten, können Sie grep -q in der Bedingung verwenden. Ich erwarte, dass Sie load_cache >/dev/null tun würden, wenn Sie die Ausgabe nicht möchten.

Wenn Sie die nicht-beleidigenden Werte sehen wollen, wird der Code etwas Refactoring benötigen, aber ich konzentriere mich darauf, den zentralen Job elegant und prägnant zu erledigen. Hier ist eine Skizze, hauptsächlich um Ihnen die jq Syntax dafür zu zeigen.

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 
} 

Die case verschachtelt auf der letzten Iteration zu vermeiden schlafen nicht besonders elegant ist, aber zumindest sollte sie dafür sorgen, dass der Leser wach ist./-8