Ich arbeite an einer benutzerdefinierten ZSH-Eingabeaufforderung und möchte ein Zeichen n
in einer Zeichenfolge mehrmals wiederholen (z. B. Leerzeichen zum Auffüllen). Diese Zeichenfolge wird mit gedruckt print -rP
(das -r
Flag ignoriert Echo-Escape-Konventionen und -P
führt Eingabeaufforderungserweiterungen durch).
Ich habe einen funktionierenden Code, der eine Art Zeichenfolgenersetzung verwendet, aber ich weiß nicht, wie das funktioniert. Aus irgendeinem Grund muss ich die Anzahl der Zeichen, die ich drucken möchte, mit zwei multiplizieren, was sich wie ein Hack anfühlt.
$ n=3
$ c='a'
$ print -rP "${(l:$n::$c:)}" # why doesn't this work?
ca
$ print -rP "${(l:(( $n * 2 ))::$c:)}" # but this does?
aaa
Also, 1) warum funktioniert dies, wenn es mit zwei multipliziert wird, und 2) was ist die richtige Syntax zum Wiederholen eines Zeichens innerhalb einer Zeichenfolge?
Antwort1
1) warum funktioniert das, wenn man es mit zwei multipliziert,
Die Erweiterung "${(l:3::$c:)}"
erweitert sich zu , c$c
während "${(l:3*2::$c:)}"
sich zu erweitert $c$c$c
. Wenn die Option PROMPT_SUBST
gesetzt ist und diese Zeichenfolge als Teil einer Eingabeaufforderungszeichenfolge verwendet wird, wird sie für die Parametererweiterung, Befehlsersetzung und arithmetische Erweiterung ausgewertet. Wenn also c=a
, dann c$c
wird ca
und $c$c$c
wird aaa
.
Test mit XTRACE
Set:
$ n=3 c=a zsh -o PROMPT_SUBST -xc 'print -rP -- "${(l:n::$c:)}"'
+zsh:1> print -rP -- 'c$c'
ca
$ n=3 c=a zsh -o PROMPT_SUBST -xc 'print -rP -- "${(l:n*2::$c:)}"'
+zsh:1> print -rP -- '$c$c$c'
aaa
und 2) was ist die richtige Syntax zum Wiederholen eines Zeichens innerhalb einer Zeichenfolge?
Das l
Parametererweiterungsflag kann auf dieselbe Weise verwendet werden, wie Sie es bereits verwenden. Das p
Flag sollte jedoch verwendet werden, um zuzulassen, $c
dass das Zeichenfolgenargument als Wert der Variablen c
vor dem Auffüllen verwendet wird (danke @StéphaneChazelas für den Hinweis).
$ n=3 c=a zsh -xc 'print -r -- "${(pl:n::$c:)}"'
+zsh:1> print -r -- aaa
aaa
Beachten Sie, dass dies die einzige Form der Parametererweiterung ist, die von dieser Konstruktion akzeptiert wird, wie man zshexpn
(im Abschnitt über Parametererweiterungsflags) beschrieben:
p
Erkennen Sie dieselben Escape-Sequenzen wie dieAlternativ können mit dieser Option String-Argumente in der Form vorliegen,
$var
in der der Wert der Variablen ersetzt wird. Beachten Sie, dass diese Form streng ist; das String-Argument unterliegt keiner allgemeinen Parametererweiterung.
Antwort2
Mit Ihrer ursprünglichen Notation können Sie erreichen, was Sie wollten, indem Sie p
an derAnfangder Parameterflags
print "${(pl:$n::$c:)}"
Weitere Informationen und einige andere nützliche Beispiele finden Sie im Abschnitt5.4.6: Noch mehr ParameterflagsInKapitel 5: Substitutionendes zsh-Handbuchs. Dort wird Großbuchstaben erwähnt P
, aber nicht p
:
Hier sind ein paar andere Parameterflags; ich wiederhole einige davon. Ein sehr nützliches Flag ist, t
Ihnen den Typ eines Parameters mitzuteilen. Dies kam auch in Kapitel 3 vor. Die häufigste Verwendung besteht darin, den grundlegenden Typ des Parameters zu testen, bevor Sie versuchen, ihn zu verwenden:
if [[ ${(t)myparam} != *assoc* ]]; then
# $myparam is not an associative array. Do something about it.
fi
Ein weiterer sehr nützlicher Typ ist zum linken oder rechten Auffüllen einer Zeichenfolge auf eine angegebene Länge und optional mit einer angegebenen Füllzeichenfolge, die anstelle eines Leerzeichens verwendet werden soll. Sie können sogar eine einmalige Zeichenfolge angeben, die direkt neben der betreffenden Zeichenfolge eingefügt werden soll.
foo='abcdefghij'
for (( i = 1; i <= 10; i++ )); do
goo=${foo[1,$i]}
print ${(l:10::X::Y:)goo} ${(r:10::X::Y:)goo}
done
druckt das ziemlich hübsche aus:
XXXXXXXXYa aYXXXXXXXX
XXXXXXXYab abYXXXXXXX
XXXXXXYabc abcYXXXXXX
XXXXXYabcd abcdYXXXXX
XXXXYabcde abcdeYXXXX
XXXYabcdef abcdefYXXX
XXYabcdefg abcdefgYXX
XYabcdefgh abcdefghYX
Yabcdefghi abcdefghiY
abcdefghij abcdefghij
Beachten Sie, dass diese Doppelpunkte (die auch andere Zeichen sein können, wie ich für die Flags ( s
) und ( ) erklärt habe) immer paarweise vor und nach dem Argument auftreten, sodass bei drei Argumenten die Doppelpunkte dazwischen verdoppelt werden. Sie können den Teil und den Teil weglassen und sehen, was passiert. Die Füllzeichenfolgen müssen keine einzelnen Zeichen sein; wenn sie nicht eine bestimmte Anzahl von Malen in den Füllraum passen, wird die letzte Wiederholung am Ende abgeschnitten, das am weitesten vom eingefügten Parameterargument entfernt ist.j
:Y:
:X:
Zwei Parameter teilen der Shell mit, dass mit dem Wert der Parametersubstitution etwas Besonderes geschehen soll. Das P
Flag ( ) erzwingt, dass der Wert als Parametername behandelt wird, sodass der Effekt einer doppelten Substitution erzielt wird:
% final=string
% intermediate=final
% print ${(P)intermediate}
string
Das ist ein bisschen so, als ob $intermediate
wir das wären, was in ksh als ein bezeichnet wird nameref
, ein Parameter, der als Referenz auf einen anderen Parameter markiert ist. Zsh könnte irgendwann auch solche haben; es gibt Stellen, an denen sie wesentlich praktischer sind als die (P)
Flagge.
Ein mächtigeres Flag ist ( e
), das eine erneute Überprüfung des Wertes für alle Formen der Einzelwortsubstitution erzwingt. Zum Beispiel:
% foo='$(print $ZSH_VERSION)'
% print ${(e)foo}
4.0.2
Der Wert wurde $foo
erneut überprüft. An diesem Punkt wurde die Befehlsersetzung gefunden und ausgeführt.
Die verbleibenden Flags sind ein paar einfache spezielle Formatierungstricks: Array-Elemente mit ( o
) in normaler lexikalischer (Zeichen-)Reihenfolge anordnen, mit ( ) in umgekehrter Reihenfolge anordnen O
, dasselbe unabhängig von Groß- und Kleinschreibung mit ( oi
) bzw. ( Oi
) tun, Prompt %
-Escapes mit ( %
) erweitern (leicht zu merken), Backslash-Escapes wie print mit p erweitern, alle Zeichen mit ( U
) in Großbuchstaben oder mit ( L
) in Kleinbuchstaben zwingen, das erste Zeichen des Strings oder jedes Array-Elements mit ( C
) groß schreiben, Sonderzeichen als Escape-Sequenzen mit ( V
) anzeigen. Das sollte für den Anfang reichen.