Ich habe das folgende einfache Skript, in dem ich eine Schleife ausführe und eine pflegen möchte COUNTER
. Ich kann nicht herausfinden, warum der Zähler nicht aktualisiert wird. Liegt es an der Subshell, die erstellt wird? Wie kann ich das möglicherweise beheben?
#!/bin/bash
WFY_PATH=/var/log/nginx
WFY_FILE=error.log
COUNTER=0
grep 'GET /log_' $WFY_PATH/$WFY_FILE | grep 'upstream timed out' | awk -F ', ' '{print $2,$4,$0}' | awk '{print "http://domain.com"$5"&ip="$2"&date="$7"&time="$8"&end=1"}' | awk -F '&end=1' '{print $1"&end=1"}' |
(
while read WFY_URL
do
echo $WFY_URL #Some more action
COUNTER=$((COUNTER+1))
done
)
echo $COUNTER # output = 0
Antworten:
Erstens erhöhen Sie den Zähler nicht. Ändern
COUNTER=$((COUNTER))
inCOUNTER=$((COUNTER + 1))
oderCOUNTER=$[COUNTER + 1]
wird es erhöhen.Zweitens ist es schwieriger, Subshell-Variablen an den Angerufenen zurückzugeben, wie Sie vermuten. Variablen in einer Unterschale sind außerhalb der Unterschale nicht verfügbar. Dies sind lokale Variablen für den untergeordneten Prozess.
Eine Möglichkeit, dies zu lösen, besteht darin, eine temporäre Datei zum Speichern des Zwischenwerts zu verwenden:
quelle
$[...]
veraltet ist? Gibt es eine alternative Lösung?$[...]
wurde von verwendet,bash
bevor$((...))
von der POSIX-Shell übernommen wurde. Ich bin nicht sicher, ob es jemals offiziell veraltet war, aber ich kann es in derbash
Manpage nicht erwähnen , und es scheint nur aus Gründen der Abwärtskompatibilität unterstützt zu werden....
GEPRÜFTE BASH: Centos, SuSE, RH
quelle
$[ ]
Syntax veraltet. stackoverflow.com/questions/10515964/…ist ein ziemlich ungeschicktes Konstrukt in der modernen Programmierung.
sieht "moderner" aus. Sie können auch verwenden
wenn Sie denken, dass dies die Lesbarkeit verbessert. Manchmal gibt Bash zu viele Möglichkeiten, Dinge zu tun - Perl-Philosophie, nehme ich an -, wenn der Python "es gibt nur einen richtigen Weg, dies zu tun" vielleicht angemessener ist. Das ist eine umstrittene Aussage, wenn es jemals eine gab! Wie auch immer, ich würde vorschlagen, dass das Ziel (in diesem Fall) nicht nur darin besteht, eine Variable zu erhöhen, sondern (allgemeine Regel) auch Code zu schreiben, den jemand anderes verstehen und unterstützen kann. Konformität trägt wesentlich dazu bei.
HTH
quelle
Versuchen zu benutzen
anstatt
quelle
let "COUNTER++"
(( COUNTER++ ))
(kein Dollarzeichen)(( COUNTER++ ))
aber als ich darauf umgestiegen bin, hatCOUNTER=$((COUNTER + 1))
es funktioniert.GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Ich denke, dieser einzelne awk-Aufruf entspricht Ihrer
grep|grep|awk|awk
Pipeline: Bitte testen Sie ihn. Ihr letzter awk-Befehl scheint überhaupt nichts zu ändern.Das Problem mit COUNTER ist, dass die while-Schleife in einer Subshell ausgeführt wird, sodass alle Änderungen an der Variablen beim Beenden der Subshell verschwinden. Sie müssen auf den Wert von COUNTER in derselben Subshell zugreifen. Oder befolgen Sie den Rat von @ DennisWilliamson, verwenden Sie eine Prozessersetzung und vermeiden Sie die Subshell insgesamt.
quelle
quelle
Anstatt eine temporäre Datei zu verwenden, können Sie
while
mithilfe der Prozessersetzung vermeiden, eine Unterschale um die Schleife zu erstellen .Übrigens sollten Sie in der Lage sein, all das
grep, grep, awk, awk, awk
in ein einziges zu verwandelnawk
.Ab Bash 4.2 gibt es eine
lastpipe
Option, diequelle
lastpipe
. Übrigens sollten Sie wahrscheinlich verwenden"${PIPESTATUS[@]}"
(at anstelle von Sternchen).minimalistisch
quelle
Das ist alles was Sie tun müssen:
Hier ist ein Auszug aus Learning the Bash Shell , 3. Auflage, S. 147, 148:
..........................
Siehe http://www.safaribooksonline.com/a/learning-the-bash/7572399/
quelle
if
Aussage verwendet habe:if [[ $((needsComma++)) -gt 0 ]]; then printf ',\n'; fi
Richtig oder falsch, dies ist die einzige Version, die zuverlässig funktioniert hat.i=1; while true; do echo $((i++)); sleep .1; done
if (( needsComma++ > 0 )); then
oderif (( needsComma++ )); then
Dies ist ein einfaches Beispiel
quelle
Es scheint, dass Sie
counter
das Skript nicht aktualisiert habencounter++
quelle
Es gab zwei Bedingungen, die dazu führten, dass der Ausdruck
((var++))
für mich fehlschlug:Wenn ich bash auf den strengen Modus (
set -euo pipefail
) setze und mein Inkrement bei Null (0) beginne .Das Beginnen bei eins (1) ist in Ordnung, aber Null bewirkt, dass das Inkrement "1" zurückgibt, wenn "++" ausgewertet wird, was im strengen Modus ein Fehlercode für den Rückkehrcode ungleich Null ist.
Ich kann dieses Verhalten entweder nutzen
((var+=1))
oder ihmvar=$((var+1))
entkommenquelle
Das Quellenskript hat ein Problem mit der Subshell. Erstes Beispiel: Sie benötigen wahrscheinlich keine Unterschale. Aber wir wissen nicht, was unter "Noch mehr Action" verborgen ist. Die beliebteste Antwort hat einen versteckten Fehler, der die E / A erhöht und nicht mit Subshell funktioniert, da der Couter innerhalb der Schleife wiederhergestellt wird.
Fügen Sie kein '\' - Zeichen hinzu, da dies den Bash-Interpreter über die Fortsetzung der Leitung informiert. Ich hoffe es wird dir oder irgendjemandem helfen. Aber meiner Meinung nach sollte dieses Skript vollständig in ein AWK-Skript konvertiert oder mit Regexp oder Perl in Python umgeschrieben werden, aber die Popularität von Perl über Jahre hinweg wird beeinträchtigt. Mach es besser mit Python.
Korrigierte Version ohne Subshell:
Version mit Subshell, wenn es wirklich benötigt wird
quelle