Wiederholen Sie den Zeichensatz n-mal in der ZSH-Eingabeaufforderung

Wiederholen Sie den Zeichensatz n-mal in der ZSH-Eingabeaufforderung

Ich arbeite an einer benutzerdefinierten ZSH-Eingabeaufforderung und möchte ein Zeichen nin einer Zeichenfolge mehrmals wiederholen (z. B. Leerzeichen zum Auffüllen). Diese Zeichenfolge wird mit gedruckt print -rP(das -rFlag ignoriert Echo-Escape-Konventionen und -Pfü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$cwährend "${(l:3*2::$c:)}"sich zu erweitert $c$c$c. Wenn die Option PROMPT_SUBSTgesetzt 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$cwird caund $c$c$cwird aaa.

Test mit XTRACESet:

$ 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 lParametererweiterungsflag kann auf dieselbe Weise verwendet werden, wie Sie es bereits verwenden. Das pFlag sollte jedoch verwendet werden, um zuzulassen, $cdass das Zeichenfolgenargument als Wert der Variablen cvor 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 die printintegrierten Zeichenfolgenargumente für alle unten beschriebenen Flags, die diesem Argument folgen.

Alternativ können mit dieser Option String-Argumente in der Form vorliegen, $varin 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 pan 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, tIhnen 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 PFlag ( ) 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 $intermediatewir 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 $fooerneut ü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.

verwandte Informationen