我正在處理自訂 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