zsh プロンプトで文字を n 回繰り返す

zsh プロンプトで文字を n 回繰り返す

私はカスタム ZSH プロンプトに取り組んでおり、文字列内で char 回繰り返すことを望んでいます(パディング用のスペースなど)。この文字列は、(フラグはエコー エスケープ規則を無視し、フラグはプロンプト拡張を実行します)nで印刷されます。print -rP-r-P

何らかの文字列置換を使用する実用的なコードがありますが、それがどのように機能するかはわかりません。何らかの理由で、印刷する文字数を 2 倍にする必要があるため、ハックのように感じます。

$ 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

では、1) なぜこれを 2 倍にすると機能するのでしょうか。2) 文字列内で文字を繰り返す正しい構文は何でしょうか。

答え1

1) なぜこれを2倍にすると機能するのか

展開"${(l:3::$c:)}"は に展開されますc$cが、"${(l:3*2::$c:)}"は に展開されます$c$c$c。 オプションPROMPT_SUBSTが設定され、この文字列がプロンプト文字列の一部として使用される場合、パラメータ展開、コマンド置換、および算術展開に対して評価されます。 したがって の場合c=a、 はc$cになりca$c$c$cになりますaaa

セットでテストXTRACE:

$ 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

2) 文字列内で文字を繰り返す正しい構文は何ですか?

パラメータl拡張フラグは、これまでと同じように使用できます。ただし、このpフラグは、$c文字列引数をパディング前の変数の値として取得できるようにするために使用する必要がありますc(この点を指摘してくれた @StéphaneChazelas に感謝します)。

$ n=3 c=a zsh -xc 'print -r -- "${(pl:n::$c:)}"'
+zsh:1> print -r -- aaa
aaa

これは、この構造で受け入れられる唯一のパラメータ拡張形式であることに注意してくださいman zshexpn(パラメータ拡張フラグに関するセクションを参照)。

pprintこの引数に続く、以下で説明するフラグのいずれかの文字列引数の組み込み   と同じエスケープ シーケンスを認識します。

あるいは、このオプションを使用すると、文字列引数は、$var変数の値が置換される形式になる場合があります。この形式は厳密であることに注意してください。文字列引数は、一般的なパラメータ展開を受けません。

答え2

オリジナルの表記法を使用するとp始まりパラメータフラグの

 print "${(pl:$n::$c:)}"

詳しい情報とその他の便利な例については、セクションをご覧ください。5.4.6: さらに多くのパラメータフラグ第5章 代替zsh ガイドの。大文字については触れていPますが、p:


他にもパラメータ フラグがいくつかあります。そのうちのいくつかは繰り返して説明します。非常に便利なフラグは、tパラメータの型を示すものです。これは第 3 章でも取り上げました。最も一般的な使用法は、パラメータを使用する前にその基本型をテストすることです。

  if [[ ${(t)myparam} != *assoc* ]]; then
    # $myparam is not an associative array.  Do something about it.
  fi

もう 1 つの非常に便利なタイプは、文字列の左または右に指定された長さでパディングし、オプションでスペースの代わりに使用する指定された埋め込み文字列を使用するタイプです。問題の文字列のすぐ隣に配置される 1 回限りの文字列を指定することもできます。

  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

かなりきれいなものを出力します:

  XXXXXXXXYa aYXXXXXXXX
  XXXXXXXYab abYXXXXXXX
  XXXXXXYabc abcYXXXXXX
  XXXXXYabcd abcdYXXXXX
  XXXXYabcde abcdeYXXXX
  XXXYabcdef abcdefYXXX
  XXYabcdefg abcdefgYXX
  XYabcdefgh abcdefghYX
  Yabcdefghi abcdefghiY
  abcdefghij abcdefghij

sこれらのコロン (( ) および ( ) フラグで説明したように、他の文字でもかまいませんj) は常に引数の前後にペアで出現するため、引数が 3 つの場合は、その間のコロンが 2 倍になります。 の:Y:部分と の:X:部分を省略して、何が起こるかを確認できます。 充填文字列は単一の文字である必要はありません。充填スペースに正確な回数収まらない場合、最後の繰り返しは、挿入されるパラメーター引数から最も遠い端で切り捨てられます。

2 つのパラメータは、パラメータ置換の値で特別な処理を実行することをシェルに指示します。 ( P) フラグは、値をパラメータ名として扱うように強制し、二重置換の効果を得ます。

  % final=string
  % intermediate=final
  % print ${(P)intermediate}
  string

$intermediateこれは、 ksh で と呼ばれるもの、つまり別のパラメータへの参照としてマークされたパラメータに少し似ていますnameref。Zsh にも最終的には が追加されるかもしれません。フラグよりもずっと便利な場所があります(P)

より強力なフラグは(e)で、これはすべての形式の単語置換に対して値の再スキャンを強制します。たとえば、

  % foo='$(print $ZSH_VERSION)'
  % print ${(e)foo}
  4.0.2

の値が$foo再検査され、その時点でコマンド置換が見つかり、実行されました。

残りのフラグは、いくつかの簡単な特別な書式設定トリックです。配列要素を通常の字句 (文字) 順に並べるには ( o)、逆順に並べるには ( O)、大文字と小文字を区別せずに同じ処理をするにはそれぞれ ( oi) または ( Oi)、プロンプト エスケープを展開するに%は ( %) (覚えやすい)、print と同じように p を使用してバックスラッシュ エスケープを展開するには ( )、すべての文字を大文字にするには ( U)、小文字にするには ( L)、文字列の最初の文字または各配列要素を大文字にするには ( C)、特殊文字をエスケープ シーケンスとして表示するには ( V) を使用します。これで十分でしょう。

関連情報