2017-06-06 4 views
0

Ich habe eine Funktion, die mir eine Liste von IPs gibt und für jede IP in meiner Liste möchte ich eine Abfrage ausführen. Das Problem, das ich habe, ist sein einziges Durchschleifen (1) der Ergebnisse und nicht der Rest.bash scripting - Wie man Ergebnisse innerhalb einer Funktion durchläuft

getPartition() 
{ 
    _knife=$(which knife); 
    _grep=$(which grep); 
    _awk=$(which awk); 
    cd ~/home/foo/.chef 
    local result=$(${_knife} search "chef_environment:dev AND role:myapp AND ec2_region:us-east-1" | ${_grep} IP | ${_awk} '{ print $2 }'); 
    read -a servers <<< $result; 
    echo "Checking ${#servers[@]} servers"; 
    for i in ${servers[@]}; 
    do 
     local host='10.1.2.123' 
     local db='mystate' 
     _mongo=$(which mongo); 
     echo -n "$i"; 
     local exp="db.foobarcluster_servers.find(
     {\"node_host\":\"${i}\",\"node_type\":\"PROCESS\",\"region\":\"us-east-1\",\"status\":\"ACTIVE\"},{\"partition_range_start\":1,\"partition_range_end\":1, _id:0}).pretty();"; 
     ${_mongo} ${host}/${db} --eval "$exp" | grep -o -e "{[^}]*}"; 
    done 
} 

Also, ich versuchte, mit for, aber es ist nur läuft die Abfrage für (1) die (5) Hosts aufgeführt.

Ich kann für result in meiner Ausgabe sehen, dass die Liste der IP-Adressen wie folgt aussehen:

+ local 'result=10.8.3.34 
10.8.2.161 
10.8.3.514 
10.8.4.130 
10.8.2.173' 

Also, ich bin nur Ergebnisse für (1) der IP-Adressen der Rückkehr sollte es sein (5) von sie, weil ich 5 IPs:

+ read -a servers 
+ echo 'Checking 1 servers' 
Checking 1 servers 
+ for i in ${servers[@]} 
+ local host=10.1.2.130 
+ local db=mystate 
++ which mongo 
+ _mongo=/usr/local/bin/mongo 
+ echo -n 10.8.3.34 
10.8.3.34+ local 'exp=db.foobarcluster_servers.find(
     {"node_host":"10.8.3.34","node_type":"PROCESS","region":"us-east-1","status":"ACTIVE"},{"partition_range_start":1,"partition_range_end":1, _id:0}).pretty();' 
+ /usr/local/bin/mongo 10.8.3.34/mystate --eval 'db.foobarcluster_servers.find(
     {"node_host":"10.8.3.34","node_type":"PROCESS","region":"us-east-1","status":"ACTIVE"},{"partition_range_start":1,"partition_range_end":1, _id:0}).pretty();' 
+ grep -o -e '{[^}]*}' 
{ "partition_range_start" : 31, "partition_range_end" : 31 } 
+ set +x 

Ergebnisse:

{ "partition_range_start" : 31, "partition_range_end" : 31 } 

ich erwarte:

{ "partition_range_start" : 31, "partition_range_end" : 31 } 
{ "partition_range_start" : 32, "partition_range_end" : 32 } 
{ "partition_range_start" : 33, "partition_range_end" : 33 } 
{ "partition_range_start" : 34, "partition_range_end" : 34 } 
{ "partition_range_start" : 35, "partition_range_end" : 35 } 

Wie kann ich meine IPs effektiv durchlaufen? Habe ich result richtig als Variable eingerichtet, um diese Liste von IPs zu halten?

+0

Was ist die Ausgabe von '$ {Server [@])'? –

Antwort

1

gute Idee, unter Verwendung von set -x - eine weitere gute Debugging-Taktik (die auch das Lesen von set -x erleichtert) wäre das Auskommentieren von Teilen, die für das Problem nicht relevant sind (z. Machen Sie die for Schleife einfach drucken Sie ihre Iterationen, hart-Code den Wert result, etc.) zu versuchen, das Problem einzugrenzen.

Wenn ich versuche, zu replizieren, was Sie selbst tun:

demo() { 
    local result='10.8.3.34 
10.8.2.161 
10.8.3.514 
10.8.4.130 
10.8.2.173' 
    read -a servers <<< $result 
    echo "Checking ${#servers[@]} servers" 
    for i in ${servers[@]}; do 
    echo "$i" 
    done 
} 

Welche (mit set -x) ausgibt:

$ demo 
+ demo 
+ local 'result=10.8.3.34 
10.8.2.161 
10.8.3.514 
10.8.4.130 
10.8.2.173' 
+ read -a servers 
+ echo 'Checking 5 servers' 
Checking 5 servers 
+ for i in '${servers[@]}' 
+ echo 10.8.3.34 
10.8.3.34 
+ for i in '${servers[@]}' 
+ echo 10.8.2.161 
10.8.2.161 
+ for i in '${servers[@]}' 
+ echo 10.8.3.514 
10.8.3.514 
+ for i in '${servers[@]}' 
+ echo 10.8.4.130 
10.8.4.130 
+ for i in '${servers[@]}' 
+ echo 10.8.2.173 
10.8.2.173 

Mit anderen Worten, Sie den Code erscheint geteilt wie zu funktionieren erwartet. Vielleicht gibt es einen Tippfehler, den du beim Transkribieren korrigiert hast?


Eine wichtige Sache (pro help read) zu beachten ist, dass readLiest eine Zeile von der Standardeingabe ... die Leitung als mit Wort Aufteilung in Felder aufgeteilt“. Mit anderen Worten, ein mehrzeiliger Eingang wird nicht durch einen Aufruf an read gelesen, nur die erste Zeile.Wir können dies testen, indem die demo Funktion Tweaking oben zu verwenden:

read -a servers <<< "$result" 

, die den Ausgang verursacht Sie beschreiben:

$ demo 
+ demo 
+ local 'result=10.8.3.34 
    10.8.2.161 
    10.8.3.514 
    10.8.4.130 
    10.8.2.173' 
+ read -a servers 
+ echo 'Checking 1 servers' 
Checking 1 servers 
+ for i in '${servers[@]}' 
+ echo 10.8.3.34 
10.8.3.34 

Also das ist wahrscheinlich die Quelle Ihrer Frage - von $result zitiert (die in der Regel ist eine gute Idee) read respektiert die Zeilenumbrüche, die die Elemente trennen, und hört auf zu lesen, nachdem sie den ersten gesehen hat.

Verwenden Sie stattdessen die readarray command, die für solche Aufgaben mehr vernünftiges Verhalten hat. Es wird "lesen Zeilen aus einer Datei in eine Array-Variable", anstatt nach der ersten Zeile zu stoppen.

Sie können dann die Umleitung des Schreibens zu result, als auch, und gerade Rohr direkt in readarray überspringen:

readarray -t servers < <(
    ${_knife} search "chef_environment:dev AND role:myapp AND ec2_region:us-east-1" 
    | ${_grep} IP | ${_awk} '{ print $2 }') 
+0

danke für den Zusammenbruch und zeige 'readarray' als ein Beispiel. das funktioniert gut für mich. – noober

1

es ist, weil Lese nur bis zum ersten Eingangszeilentrennzeichen liest „\ n“ Hinzufügen Option -d ‚‘, liest, bis die Eingabe von Ende

result=serv1$'\n'serv2$'\n'serv3 

read -a servers <<< $result 
printf "<%s>\n" "${servers[@]}" 

read -d '' -a servers <<< $result 
printf "<%s>\n" "${servers[@]}" 

Es auch ist Readarray gebautet, die eine Anordnung zum Lesen verwendet werden kann,

readarray -t servers <<< $result 
printf "<%s>\n" "${servers[@]}" 

-t die Zeilenumbrüche für jedes Element des Arrays entfernen

1

Das Problem, dass ...

read -a servers <<< $result 
die erste Zeile nur

liest ist in das Array

Ändern Sie diese Zeile zu ...

servers=($result) 

Dies konvertiert alle durch Leerzeichen begrenzten Werte in $result in ein Array-Element. Effektiv servers=(<ip> <ip> <ip> <ip> <ip>)

+0

'Ergebnis' ist kein Array. – dimo414

+0

@ dimo414 guter Fang –

Verwandte Themen