Повторите символ n раз в приглашении zsh

Повторите символ n раз в приглашении zsh

Я работаю над пользовательским приглашением ZSH и хочу повторить символ nраз в строке (например, пробелы для заполнения). Эта строка печатается с print -rP( -rфлаг игнорирует соглашения об эхо-вызове, а -Pфлаг выполняет расширения приглашения).

У меня есть рабочий код, использующий какую-то подстановку строк, но я не знаю, как он работает. По какой-то причине мне приходится умножать количество символов, которые я хочу напечатать, на два, что похоже на хак.

$ 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) каков правильный синтаксис для повторения символа в строке?

решение1

1) почему это работает при умножении на два,

Расширение "${(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(в разделе о флагах расширения параметров):

p   Распознавать те же управляющие последовательности, что и printвстроенные в строковые аргументы для любого из флагов, описанных ниже, которые следуют за этим аргументом.

В качестве альтернативы, с этой опцией строковые аргументы могут быть в форме , $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

Другой очень полезный тип — для левого или правого заполнения строки до указанной длины и, при необходимости, с указанной строкой заполнения, которая будет использоваться вместо пробела; вы даже можете указать одноразовую строку, которая будет идти сразу за нужной строкой.

  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) ) всегда встречаются парами до и после аргумента, так что при трех аргументах двоеточия между ними удваиваются. Вы можете пропустить часть :Y:и :X:часть и посмотреть, что произойдет. Строки заполнения не обязательно должны быть одиночными символами; если они не помещаются точное количество раз в пространство заполнения, последнее повторение будет усечено на конце, наиболее удаленном от вставляемого аргумента параметра.

Два параметра сообщают оболочке, что вы хотите сделать что-то особенное со значением подстановки параметра. Флаг ( P) заставляет значение рассматриваться как имя параметра, так что вы получаете эффект двойной подстановки:

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

Это немного похоже $intermediateна то, что в ksh называется a 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). Этого должно быть достаточно, чтобы приступить к работе.

Связанный контент