我正在处理自定义 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 时会起作用,2)在字符串中重复字符的正确语法是什么?
答案1
1)为什么乘以二会有效,
展开式"${(l:3::$c:)}"
展开为c$c
while"${(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
或者,使用此选项,字符串参数可以采用以下形式,
$var
在这种情况下,将替换变量的值。请注意,此形式是严格的;字符串参数不进行一般参数扩展。
答案2
使用你原来的符号,你可以实现你想要的,p
使用开始参数标志
print "${(pl:$n::$c:)}"
有关更多信息和其他一些有用的示例,请参阅 部分5.4.6:更多参数标志在第5章:替补zsh 指南。它提到了 uppercase 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:
一部分,看看会发生什么。填充字符串不需要是单个字符;如果它们在填充空间中不适合准确的次数,则最后一次重复将在距插入的参数参数最远的一端被截断。
两个参数告诉 shell 您希望对参数替换的值执行一些特殊操作。 ( 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
进行相同的大小写无关,展开提示-用 ( ) 转义(容易记住),像 print 用 p 那样扩展反斜杠转义,用 ( ) 强制所有字符大写或用 ( ) 小写,用 ( ) 大写字符串或每个数组元素的第一个字符,显示特殊字符作为转义序列,带有 ( )。这应该足以继续下去了。oi
Oi
%
%
U
L
C
V