Zsh 開發指南(第五篇 數組)

導讀

瞭解完結構比較簡單的字符串後,咱們來看更復雜一些的數組。其實字符串在 zsh 中也能夠當字符數組操做,但不多有須要把字符串當數組來處理的場景。本篇中主要講的是字符串數組,複雜度要比單個字符串高一些。git

在實際的腳本編寫中,較少須要處理單個的字符串。每每須要處理從各個地方過來的大量文本,不可避免會用到數組。用好數組,會讓文本處理工做事半功倍。github

本篇只涉及數組的基礎用法。vim

數組定義

數組能夠直接賦值使用,不須要提早聲明。等號和小括號之間不能有空格,小括號中的元素以空格隔開。c#

% array=(a bc ccc dddd)
# 用 $array 便可訪問數組所有元素,輸出時元素以空格分隔
% echo $array
a bc ccc dddd

# 使用 print -l 能夠每行輸出一個元素
% print -l $array
a
bc
ccc
dddd

# 輸出數組中的元素個數,用法和取字符串長度同樣
% echo $#array
4

# 包含帶空格的字符串
% array=(a "bc ccc" dddd)
% print -l $array
a
bc ccc
dddd

# 能夠換行賦值,但若是行中間有空格,依然須要加引號
% array=(
> a
> bb
> "c c c"
> dddd
> )複製代碼

元素讀寫

% array=(a bc ccc dddd)

# 用法和取字符串的第幾個字符同樣,從 1 開始算
% echo $array[3]
ccc
# -1 依然是最後一個元素,-2 是倒數第二個,以此類推
% echo $array[-1]
dddd

% array[3]=CCC

# 若是賦值的內容是一個空的小括號,則刪除該元素
% array[2]=()

% print -l $array
a
CCC
dddd

# 用 += 爲數組添加一個新元素
% array+=eeeee
% print -l $array
a
CCC
dddd
eeeee

# 用 unset 能夠刪除整個數組
% unset array

# array 變量變成未定義狀態
% echo $+array
0複製代碼

數組拼接

% array1=(a b c d)
% array2=(1 2 3 4)

# 用 += 拼接數組
% array1+=(e f g)
% echo $array1
a b c d e f g

# 拼接另外一個數組,小括號不能夠省略,不然 array1 會被轉成一個字符串
% array2+=($array1)
% echo $#array2
11

# 去掉引號後,array1 被轉成了一個字符串
% array2+=$array1
% echo $#array2
12
% echo $array2[12]
a b c d e f g


# 字符串能夠直接拼接數組而轉化成數組
% str=abcd
% str+=(1234)

% echo $#str
2複製代碼

數組遍歷

% array1=(a bb ccc dddd)
% array2=(1 2 3)

# 用 for 能夠直接遍歷數組,小括號不可省略
% for i ($array1) {
> echo $i
> }
a
bb
ccc
dddd

# 小括號裏能夠放多個數組,依次遍歷
% for i ($array1 $array2) {
> echo $i
> }
a
bb
ccc
dddd
1
2
3複製代碼

數組切片

數組切片和字符串切片操做方法徹底相同。數組

% array=(a bb ccc dddd)

% echo $array[2,3]
bb ccc

# 依然能夠多對多地替換元素
% array[3,-1]=(1 2 3 4)
% echo $array
a bb 1 2 3 4

# 也可使用另外一種語法,不建議使用
% echo ${array:0:3}
a bb 1複製代碼

元素查找

數組的元素查找方法,和字符串的子字符串查找語法同樣。bash

% array=(a bb ccc dddd ccc)

# 用小 i 輸出從左到右第一次匹配到的元素位置
% echo $array[(i)ccc]
3

# 若是找不到,返回數組大小 + 1
% echo $array[(i)xxx]
6

# 用大 I 輸出從右到左第一次匹配到的元素位置
% echo $array[(I)ccc]
5

# 若是找不到,返回 0 
% echo $array[(I)xxx]
0

# 能夠用大 I 判斷是否存在元素
% (( $array[(I)dddd] )) && echo good
good

% (( $array[(I)xxx] )) && echo good


% array=(aaa bbb aab bbc)
# n:2: 從指定的位置開始查找
% echo ${array[(in:2:)aa*]}
3複製代碼

元素排序

% array=(aa CCC b DD e 000 AA 3 aa 22)

# 升序排列,從小到大
% echo ${(o)array}
000 22 3 aa aa AA b CCC DD e

# 降序排列,從大到小
% echo ${(O)array}
e DD CCC b AA aa aa 3 22 000

# 加 i 的話大小寫不敏感
% echo ${(oi)array}
000 22 3 aa AA aa b CCC DD e


% array=(cc aaa b 12 115 90)
# 加 n 的話按數字大小順序排
% echo ${(on)array}
12 90 115 aaa b cc

# Oa 用於反轉數組元素的排列順序
% echo ${(Oa)array}
90 115 12 b aaa cc複製代碼

去除重複元素

% array=(ddd a bb a ccc bb ddd)

% echo ${(u)array}
ddd a bb ccc複製代碼

使用連續字符或者數值構造數組

# 大括號中的逗號分隔的字符串會被展開
% array=(aa{bb,cc,11}) && echo $array
aabb aacc aa11

# .. 會將先後的數組連續展開
% array=(aa{1..3}) && echo $array
aa1 aa2 aa3

# 第二個 .. 後的數字是展開的間隔
% array=(aa{15..19..2}) && echo $array
aa15 aa17 aa19

# 能夠從大到小展開
% array=(aa{19..15..2}) && echo $array
aa19 aa17 aa15

# 能夠添加一個或多個前導 0
% array=(aa{01..03}) && echo $array
aa01 aa02 aa03

# 單個字母也能夠像數值那樣展開,多個字母不行
% array=(aa{a..c}) && echo $array
aaa aab aac

# 字母是按 ASCII 碼的順序展開的
% array=(aa{Y..c}) && echo $array
aaY aaZ aa[ aa\ aa] aa^ aa_ aa` aaa aab aac


# 這些用法均可以用在 for 循環裏邊
% for i (aa{a..c}) {
> echo $i
> }
aaa
aab
aac複製代碼

從字符串構造數組

% str="a bb ccc dddd"

# ${=str} 能夠將 str 內容按空格切分紅數組
% array=(${=str})
% print -l $array[2,3]
bb
ccc


% str="a:bb:ccc:dddd"
# 若是是其餘分隔符,能夠設置 IFS 變量指定
% IFS=:
% array=(${=str})
% print -l $array[2,3]
bb
ccc


% str="a\nbb\nccc\ndddd"
# 若是是其餘分隔符,也能夠用 (s:x:) 指定
% array=(${(s:\n:)str})
% print -l $array[2,3]
bb
ccc


% str="a##bb##ccc##dddd"
# 分隔符能夠是多個字符
% array=(${(s:##:)str})
% print -l $array[2,3]
bb
ccc


% str="a:bb:ccc:dddd"
# 若是分隔符是 :,能夠 (s.:.)
% array=(${(s.:.)str})
% print -l $array[2,3]
bb
ccc複製代碼

從文件構造數組

test.txt 內容。微信

a
bb
ccc
dddd複製代碼

每行一個元素。ide

# f 的功能是將字符串以換行符分隔成數組
# 雙引號不可省略,否則會變成一個字符串,引號也能夠加在 ${ } 上
% array=(${(f)"$(<test.txt)"})
% print -l $array
a
bb
ccc
dddd

# 不加引號的效果
% array=(${(f)$(<test.txt)})
% print -l $array
a bb ccc dddd


# 從文件構造數組,並將每行按分隔符 : 分隔後輸出全部列
for i (${(f)"$(<test.txt)"}) {
    array=(${(s.:.)i})
    echo $array[1,-1]
}複製代碼

從文件列表構造數組

# 這裏的 * 即上一篇講的通配符,全部的用法均可以在這裏使用。
% array=(/usr/bin/vim*)
% print -l $array
/usr/bin/vim
/usr/bin/vimdiff
/usr/bin/vimtutor

# 要比 ls /usr/bin/[a-b]?? | wc -l 快不少
% array=(/usr/bin/[a-b]??) && print $#array
3複製代碼

數組交集差集

% array1=(1 2 3)
% array2=(1 2 4)

# 兩個數組的交集,只輸出兩個數組都有的元素
% echo ${array1:*array2}
1 2

# 兩個數組的差集,只輸出 array1 中有,而 array2 中沒有的元素
% echo ${array1:|array2}
3

# 若是有重複元素,不會去重
% array1=(1 1 2 3 3)
% array2=(4 4 1 1 2 2)
% echo ${array1:*array2}
1 1 2複製代碼

數組交叉合併

% array1=(a b c d)
% array2=(1 2 3)

# 從 array1 取一個,再從 array2 取一個,以此類推,一個數組取完了就結束
% echo ${array1:^array2}
a 1 b 2 c 3

# 若是用 :^^,只有一個數組取完了的話,繼續從頭取,直到第二個數組也取完了
% echo ${array1:^^array2}
a 1 b 2 c 3 d 1複製代碼

對數組中的字符串進行統一的處理

一些處理字符串的方法(主要是各類形式的截取、替換、轉換等等),也能夠用在數組上,效果是對數組中全部元素統一處理。ui

% array=(/a/b.htm /a/c /a/b/c.txt)

# :t 是取字符串中的文件名,能夠用在數組上,取全部元素的文件名
% print -l ${array:t}
b.htm
c
c.txt

# :e 是取擴展名,若是沒有沒有擴展名,結果數組中不會添加空字符串
% print -l ${array:e}
htm
txt

# 字符串替換等操做也能夠對數組使用,替換全部字符串
% print -l ${array/a/j}
/j/b.txt
/j/c
/j/b/c.txt複製代碼

:# 也能夠在數組上用,但更實用一些。spa

% array=(aaa bbb ccc)

# :# 是排除匹配到的元素,相似 grep -v
% print ${array:#a*}
bbb ccc

# 前邊加 (M),是反轉後邊的效果,即只輸出匹配到的元素,相似 grep
% print ${(M)array:#a*}
aaa

# 多個操做能夠同時進行,(U) 是把字符串轉成大寫字母
% print ${(UM)array:#a*}
AAA複製代碼

總結

本篇講的是數組的基礎用法,還有不少複雜的操做方法,之後會提到。

參考

zshwiki.org/home/script…

www.bash2zsh.com/zsh_refcard…

更新歷史

20170830:增長「使用連續字符或者數值構造數組」。

20170909:修正「從字符串構造數組」中的錯誤。

20170910:增長「從字符串構造數組」中的部份內容。

全系列文章地址:github.com/goreliu/zsh…

付費解決 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等領域相關問題,靈活訂價,歡迎諮詢,微信 ly50247。

相關文章
相關標籤/搜索