Der Wert meiner Variablen ist 0, aber ich habe ihn nicht auf 0 gesetzt

7

Heute habe ich festgestellt, dass eine meiner zsh-Funktionen nicht funktioniert. Ich habe das Problem untersucht und der Schuldige war folgender:

for i in a b
do
echo "$i"
done
0
0

Dann habe ich ein neues zsh eröffnet und dabei funktionierten die Dinge normal:

for i in a b
do
echo "$i"
done
a
b

Kann mir jemand den Grund erklären, warum sich der erste komisch verhält?

Glückliches Gesicht
quelle
3
Wurde die Variable izuvor im ersten Fall als Ganzzahl gesetzt (oder deklariert)?
Steeldriver
@steeldriver änderte ich izu weirdName13und es in der Tat das Problem behoben. Aber ich hatte nichts mit mir gemacht. Wie kann man diesen Satz rückgängig machen? Und wie kann ich meine Skripte schützen, wenn ich als Ganzzahl gesetzt bin?
HappyFace
1
@HappyFace Wenn Sie die lokalen Variablen Ihrer Funktion nicht als lokal deklariert haben , erwarten Sie, dass sie durch zufällige Dinge getrampelt werden.
Muru

Antworten:

10
% typeset -i i
% for i in a b; print $i
0
0

Variablen in zshkönnen verschiedene Typen zugewiesen werden, oben -ifür "intern als Ganzzahl darstellen", wodurch die Variable als solche dargestellt wird. Dies kann auch über erfolgen integer i. Es gibt verschiedene Möglichkeiten, um zu überprüfen, was eine Variable ist:

% print ${(t)i}
integer
% typeset -p i
typeset -i i=0

Und die übliche Shell +zu deaktivieren (siehe auch set -x, set +x) es:

% typeset +i i
% for i in a b; print $i
a
b

Es kann nützlich sein, herauszufinden, was den Typ dieser Variablen geändert hat, und diese Änderung auf einen lokalen Bereich (innerhalb einer Funktion) zu beschränken, damit der globale Namespace nicht mit zufälligen Typen verschmutzt wird, insbesondere bei häufig verwendeten wegwerfbaren Variablennamen wie z i. Es ist ziemlich einfach, den globalen Namespace zu verschmutzen, da lediglich eine Zuweisung zu einer nicht deklarierten Variablen erforderlich ist:

% () { local l=42; g=43 }
% print $l

% print $g
43

Oder jemand könnte das -gFlag unnötig zu einem hinzufügen typeset, wodurch die Variable global wird:

% () { typeset -g -i h=42 }
% for h in a b; print $h
0
0

Exportierte Variablen bleiben möglicherweise in neuen Prozessen erhalten (ein untergeordnetes Nicht-Subshell-Via forkoder ein Ersatz-Via exec), jedoch nicht der Typ:

% export -i h=42
% print $h ${(t)h}
42 integer-export

% ( print ${(t)h} )
integer-export

% exec zsh -l
% print $h ${(t)h}
42 scalar-export
Thrig
quelle
Ist es möglich, ein Skript vor dieser Verschmutzung zu schützen?
HappyFace
2
"Ein Skript" wird nach meinem Verständnis als ein anderer Prozess ausgeführt und sollte daher nicht betroffen sein. wenn Sie Random - Code sind Sourcing ( ., source, eval) in einen bestehenden Prozess dann könnte schlechter Code leicht verschmutzt die Umwelt, wobei in diesem Fall müssen Sie entweder das nicht tun, oder jede Zeile des Random - Code überprüfen , um zu sehen , was es tut
Thrig
2
Ich denke, Sie könnten es auch unset vardazu bringen, besondere Eigenschaften zu verlieren. Nun, es sei denn, es ist auch schreibgeschützt. In diesem Fall müssten Sie es typeset +r varzuerst tun . Bash und ksh könnten dasselbe Problem mit Variablen haben, die als Ganzzahlen festgelegt sind, mit derselben Lösung. Außer dass Sie darin keine unsetschreibgeschützten Variablen finden können.
Ilkkachu
1
@ilkkachu, auch in bash oder mksh, können Sie rufen Sie müssen unsetmehrmals , falls es (in denen lokale in mehreren Vorfahren Kontexten erklärt wurde (und yash, unsetungesetzt nicht, schält sie aus einer Schicht aus local(außer in , bashwenn die Variable wurde im aktuellen Kontext deklariert )).
Stéphane Chazelas
Was ist ein Kind ohne Unterschale über eine Gabel ? exportist für die Übertragung von skalaren Variablen über Execs, das ist unabhängig von Prozessen.
Stéphane Chazelas