Zsh 開發指南(第三篇 字元串處理之轉義字元和格式化輸出)
導讀
上一篇講了 zsh 的常用字元串操作,這篇開始講更為瑣碎的轉義字元和格式化輸出相關內容。包括轉義字元、引號、print、printf 的使用等等。其中很多內容沒有必要記憶,作為手冊參考即可。
轉義字元
轉義字元是很多編程語言中都有的概念,它主要解決某些字元因為沒有對應鍵盤按鍵無法直接輸出、字元本身有特殊含義(比如 、")或者顯示不直觀(比如難以區別多個空格和一個 tab)等問題。
最常用的轉義字元是
(換行)、
(回車)、 (tab)。
直接用 echo、print 或者 printf 內置命令都可以正常輸出轉義字元,但包括轉義字元的字元串需要用引號(單雙引號都可以)擴起來。
% echo Hello
WorldHello World
常用轉義字元對照表,不常用的可以去查 ASCII 碼錶,然後使用 xnn(如 x14)。(知乎專欄不支持表格,只能截圖,並且本文可能不能更新到最新版本,建議閱讀原文 Zsh 開發指南(第三篇 字元串處理之轉義字元和格式化輸出))
可以用 hexdump 命令查看字元的 ASCII 碼值。
% echo ab= | hexdump -C00000000 61 62 3d 0a |ab=.|00000004
還有一些字元是可選轉義(通常有特殊含義的字元都是如此)的,比如空格、"、、*、~、$、&、(、)、[、]、{、}、;、? 等等,即如果在引號裡邊則無需轉義(即使轉義也不出錯,轉義方法都說前邊加一個 ),但如果在引號外邊則需要轉義。謹慎起見,包含半形符號的字元串全部用引號包含即可,可以避免不必要的麻煩。
可以這樣檢查一個字元在空格外是否需要轉義,輸出的字元中前邊帶 的都是需要的。
% str=~!@#$%^&*()_+-={}|[]:;<>?,./"# -r 選項代表忽略字元串中的轉義符合# ${(q)str} 功能是為字元串中的特殊符號添加轉義符號% print -r ${(q)str}~!@#$%^&*()_+-={}|[]:;<>?,./"
單引號
單引號的左右主要是為了避免字元串里的特殊字元起作用。在單引號中,只有一個字元需要轉義,轉義符號 。所以如果字元串里包含特殊符號時,最好使用單引號包含起來,避免不必要的麻煩。但是單引號里不能再有單引號,即使加轉義符號也不行,如果字元串需要包含單引號,可以使用這幾種方法。
# 用雙引號包含% echo "ab"ab# 用轉義符號% echo aab# 同時使用單引號和轉義符號,用於包含單引號和其他特殊符號的場景% echo a"\b*?a"*?
雙引號
雙引號的作用類似單引號,但沒有單引號那麼嚴格,有些特殊字元在雙引號里可以繼續起作用。
# 以使用變數% str=abc% echo "$str"abc# 可以使用 $( ) 運行命令% echo "$(ls)"gittmp# 可以使用 ` ` 運行命令,不建議在腳本里使用 ` `% echo "`date`"Mon Aug 28 09:49:11 CST 2017# 可以使用 $(( )) 計算數值% echo "$(( 1 + 2 ))"3# 可以使用 $[ ] 計算數值% echo "$[1 + 2]"3
簡單說,$ 加各種東西的用法在雙引號里都是可以正常使用的,而其他特殊符號(比如 *、?、>)的功能通常不可用。
反引號
反引號是用來運行命令的,它會返回命令結果,以便保存到變數等等。
% str=`ls`% echo $strgittmp# 完全可以用 $( ) 取代% str=$(ls)% echo $strgittmp
反引號的功能和 $( ) 功能基本一樣,但 $( ) 可以嵌套,而反引號不可以,而且反引號看起來更費事,某些字體中的反引號和單引號差別不大。所以在腳本里不建議使用反引號。
print 命令用法
print 是類似 echo 的內部命令(echo 命令很簡單,不作介紹),但功能比 echo 強大很多。完全可以使用 print 代替 echo。
不加參數的 print 和 echo 的功能基本一樣,但如果字元串里包含轉義字元,某些情況可能不一致。如果需要輸出轉義字元,盡量統一使用 print,避免不一致導致的麻煩。
% print Line one
Line twoLine oneLine two# echo 的輸出和 print 不一致% echo Line one
Line twoLine oneLine two
print 有很多參數,在 zsh 里輸入 print - 然後按 tab 即可查看選項幫助(如果沒有效果,需要配置 .zshrc 里的補全選項,網上有很多現成的配置)。
# - 後直接按 tab,C 是補全上去的% print -C -- option ---C -- print arguments in specified number of columns-D -- substitute any arguments which are named directories using ~ notation-N -- print arguments separated and terminated by nulls...
print 命令選項功能介紹
這裡以常用程度的順序依次介紹所有的選項,另外文末有「print 選項列表」方便查詢。
-l 用於分行輸出字元串。
# 每個字元串一行,字元串是用空格隔開的% print -l aa bbaabb# 也可以接數組,數組相關的內容之後會講到# 命令後的多個字元串都可以用數組取代,效果是相同的% array=(aa bb)% print -l $arrayaabb
-n 用於不在輸出內容的末尾自動添加換行符(echo 命令也有這個用法)。
% print abcabc# 這個 % 高亮顯示,代表這一行末尾沒有換行符% print -n abcabc%
-m 用於只輸出匹配到的字元串。
% print -m "aa*" aabb abc aacaabb aac
-o/-O/-i 用於對字元串排序。
# print -o 對字元串升序排列% print -o a d c 1 b g 3 s1 3 a b c d g s# print -O 對字元串降序排列% print -O a d c 1 b g 3 ss g d c b a 3 1# 加 -i 參數後,對大小寫不敏感% print -oi A B C a c A B CA a A B B C c C# 不加 -i 的話小寫排在大寫的前面% print -o A B C a c A B Ca A A B B c C C
-r 用於不對字元串進行轉義。print 默認是會對轉義字元進行轉義的,加 -r 後會原樣輸出。
% print -r
-c 用於將字元串按列輸出。如果對自動決定的列數不滿意,可以用 -C 指定列數。
% print -c a bbbbb ccc ddddd ee ffffff gg hhhhhh ii jj kka ccc ee gg ii kkbbbbb ddddd ffffff hhhhhh jj
-C 用於按指定列數輸出字元串。
# 從上到下% print -C 3 a bb ccc dddd ee fa ccc eebb dddd f% print -C 3 a bb ccc dddd ee f ga dddd gbb eeccc f# 加 -a 後,改成從左向右% print -a -C 3 a bb ccc dddd ee f ga bb cccdddd ee fg
-D 用於將符合條件的路徑名轉化成帶 ~ 的格式,~ 是家目錄。
% print -D /home/goreliu/git~/git# mine 是這樣定義的 hash -d mine=/mnt/c/mine% print -D /mnt/c/mine~mine
-N 用於將輸出的字元串以 x00(null)分隔,而不是空格。這樣可能方便處理包含空格的字元串,xargs 等命令也可以接受以 x00 分隔的字元串。
% print -N aa bb ccaabbcc%% print -N aa bb cc | hexdump -C00000000 61 61 00 62 62 00 63 63 00 |aa.bb.cc.|00000009
-x 用於將行首的 tab 替換成空格。-x 是將行首的 tab 展開成空格,- x 後的參數是一個 tab 對應的空格數。
% print -x 2 abc | hexdump -C00000000 20 20 20 20 61 62 63 0a | abc.|00000008% print -x 4 abc | hexdump -C00000000 20 20 20 20 20 20 20 20 61 62 63 0a | abc.|0000000c
-X 用於將所有的 tab 替換成空格。注意不是簡單地替換成空格。比如每行有一個 tab,-X 8,那麼如果 tab 前(到行首或者上一個 tab)有 5 個字元,就補全 3 個空格,湊夠 8,這麼做是為了對齊每一列的。但如果前邊有 8 個或者 8 個以上字元,那麼依然是一個 tab 替換成 8 個字元,因為 tab 不能憑空消失,一定要轉成至少一個空格才行。如果沒理解就自己多試試找規律吧。
% print -X 2 ab abc | hexdump -C00000000 61 62 20 20 20 20 61 62 63 0a |ab abc.|0000000a% print -X 4 ab abc | hexdump -C00000000 61 62 20 20 20 20 20 20 61 62 63 0a |ab abc.|0000000c
-u 用於指定 fd 輸出。print 默認輸出到 fd 1,即 stdout,可以指定成其他 fd(2 是 stderr,其他的可以運行 ls -l /proc/$$/fd 查看。
% print -u 2 goodgood# 和重定向輸出效果一樣% print good >&2
-v 用於把輸出內容保存到變數。
# 和 str="$(print aa bb cc)" 效果一樣% print -v str aa bb cc% echo $straa bb cc
-s/-S 用於把字元串保存到歷史記錄。
% print -s ls -a% history | tail -n 1 2222 ls -a# -S 也類似,但需要用引號把命令引起來% print -S "ls -a"% history | tail -n 1 2339 ls -a
-z 用於把字元串輸出到命令行編輯區。
# _是游標位置% print -z aa bb cc% aa bb cc_
-f 用於按指定格式化字元串輸出,同 printf,用法見「printf 命令用法」。
-P 用於輸出帶顏色和特殊樣式的字元串,見「輸出帶顏色和特殊樣式的字元串」。
-b 用於辨認出 bindkey 中的轉義字元串,bindkey 是 Zle 的快捷鍵配置內容,寫腳本用不到,不作介紹。
-R 用於模擬 echo 命令,只支持 -n 和 -e 選項,通常用不到。
printf 命令用法
printf 命令很像 c 語言的 printf 函數,用於輸出格式化後的字元串。
# 輸出末尾的 % 代表該行末尾沒有換行符# printf 不會在輸出末尾添加換行符# 為了避免誤解,之後的例子省略該符號% printf ":%d %f:" 12 34.56:12 34.560000:%
printf 的第一個參數是格式化字元串,在 zsh 里輸入 printf % 後按 tab,可以看到所有支持的用法。下面只舉幾個比較常用的例子。
# 整數 浮點數 字元串% printf "%d %f %s" 12 12.34 abcd12 12.340000 abcd%# 取小數點後幾位% printf "%.1f" 12.3412.3# 科學計數法輸出浮點數% printf "%e" 12.341.234000e+01# 將十進位數字轉成十六進位輸出% printf "%x" 12c# 補齊空格或者0% printf "%5d
%05d" 12 12 1200012
我把完整的格式貼在這裡,方便搜索。
-- print format specifier -- -- leave one space in front of positive number from signed conversion- -- left adjust result. -- precision -- thousand separators* -- field width in next argument# -- alternate form% -- a percent sign+ -- always place sign before a number from signed conversion0 -- zero pad to lengthb -- as %s but interpret escape sequences in argumentc -- print the first character of the argumentE e -- double number in scientific notationf -- double numberG g -- double number as %f or %e depending on sizei d -- signed decimal number or with leading " numeric value of following charactern -- store number of printed bytes in parameter specified by argumento -- unsigned octal numberq -- as %s but shell quote results -- print the argument as a stringu -- unsigned decimal numberX x -- unsigned hexadecimal number, letters capitalized as x
輸出帶顏色和特殊樣式的字元串
用 zsh 的 print -P 可以方便地輸出帶顏色和特殊樣式的字元串,不用再和 33[41;36;1m之類莫名其妙的字元串打交道了。
# %B 加粗 %b 取消加粗# %F{red} 前景色 %f 取消前景色# %K{red} 背景色 %k 取消背景色# %U 下滑線 %u 取消下滑線# %S 反色 %s 取消反色## black or 0 red or 1# green or 2 yellow or 3# blue or 4 magenta or 5# cyan or 6 white or 7# 顯示加粗的紅色 abc% print -P %B%F{red}abcabc# 沒覆蓋到的功能可以用原始的轉義符號,可讀性比較差# 4[0-7] 背景色# 3[0-7] 前景色# 0m 正常 1m 加粗 2m 變灰 3m 斜體 4m 下滑錢 5m 閃爍 6m 快速閃爍 7m 反色# 顯示閃爍的紅底綠字 abc% print " 33[41;32;5mabc 33[0m"abc
print 選項列表
為了方便查詢,我把 print 的選項列表放在這裡。
參考
http://zsh.sourceforge.net/Guide/zshguide05.html
本文不再更新,全系列文章在此更新維護:github.com/goreliu/zshguide
付費解決 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等領域相關問題,靈活定價,歡迎諮詢,微信 ly50247。
推薦閱讀: