Zsh Development Guide (Part 5 Array)

Guide reading

After understanding the simpler structured strings, let's look at more complex arrays. In fact, strings can also be manipulated as character arrays in zsh, but there are few scenarios where strings need to be processed as arrays. In this article, we focus on string arrays, which are more complex than a single string.

In actual scripting, there is less need to deal with individual strings. Arrays are inevitably used to process large amounts of text coming from different places. If you use arrays well, you will get twice the result with half the effort in text processing.

This article deals only with the basic usage of arrays.

array define

Arrays can be assigned directly without having to be declared in advance. There should be no spaces between equal brackets and parentheses, and the elements in parentheses should be separated by spaces.

% array=(a bc ccc dddd)
# All elements of the array can be accessed with $array, and the elements are separated by spaces when they are output.
% echo $array
a bc ccc dddd

# Using print-l, you can output one element per line
% print -l $array
a
bc
ccc
dddd

# The number of elements in the output array is the same as the length of the string.
% echo $#array
4

# A string containing spaces
% array=(a "bc ccc" dddd)
% print -l $array
a
bc ccc
dddd

# You can assign values to new lines, but if there is a space in the middle of the line, you still need quotation marks.
% array=(
> a
> bb
> "c c c"
> dddd
> )

Elements read and write

% array=(a bc ccc dddd)

# The usage is the same as taking the third character of the string, counting from 1
% echo $array[3]
ccc
# - 1 is still the last element, - 2 is the penultimate, and so on.
% echo $array[-1]
dddd

% array[3]=CCC

# If the assignment is an empty parenthesis, delete the element
% array[2]=()

% print -l $array
a
CCC
dddd

# Add a new element to the array with +=.
% array+=eeeee
% print -l $array
a
CCC
dddd
eeeee

# The whole array can be deleted with unset
% unset array

# array variable becomes undefined state
% echo $+array
0

Array splicing

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

# Splice arrays with +=.
% array1+=(e f g)
% echo $array1
a b c d e f g

# Stitching another array, parentheses cannot be omitted, otherwise array1 will be converted to a string
% array2+=($array1)
% echo $#array2
11

# After removing quotation marks, array1 is converted to a string
% array2+=$array1
% echo $#array2
12
% echo $array2[12]
a b c d e f g


# Strings can be spliced directly into arrays and converted into arrays.
% str=abcd
% str+=(1234)

% echo $#str
2

Array traversal

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

# You can traverse arrays directly with for, and parentheses cannot be omitted
% for i ($array1) {
> echo $i
> }
a
bb
ccc
dddd

# Multiple arrays can be placed in parentheses and traversed in turn
% for i ($array1 $array2) {
> echo $i
> }
a
bb
ccc
dddd
1
2
3

Array slice

Array slicing and string slicing operate in exactly the same way.

% array=(a bb ccc dddd)

% echo $array[2,3]
bb ccc

# You can still replace elements many to many
% array[3,-1]=(1 2 3 4)
% echo $array
a bb 1 2 3 4

# You can also use another grammar, which is not recommended.
% echo ${array:0:3}
a bb 1

Element search

The element lookup method of an array is the same as the substring lookup grammar of a string.

% array=(a bb ccc dddd ccc)

# The first matched element position from left to right with small i output
% echo $array[(i)ccc]
3

# If not found, return the array size + 1
% echo $array[(i)xxx]
6

# Output the first matched element position from right to left with large I
% echo $array[(I)ccc]
5

# If not, return 0 
% echo $array[(I)xxx]
0

# Large I can be used to determine whether there are elements or not.
% (( $array[(I)dddd] )) && echo good
good

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


% array=(aaa bbb aab bbc)
# n:2: Start at the specified location
% echo ${array[(in:2:)aa*]}
3

Element sorting

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

# Ascending order, from small to large
% echo ${(o)array}
000 22 3 aa aa AA b CCC DD e

# Descending order, from big to small
% echo ${(O)array}
e DD CCC b AA aa aa 3 22 000

# Case insensitivity with i
% echo ${(oi)array}
000 22 3 aa AA aa b CCC DD e


% array=(cc aaa b 12 115 90)
# If n is added, the number is arranged in order of size.
% echo ${(on)array}
12 90 115 aaa b cc

# Oa is used to reverse the order of array elements
% echo ${(Oa)array}
90 115 12 b aaa cc

Removal of repetitive elements

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

% echo ${(u)array}
ddd a bb ccc

Construct arrays using continuous characters or numeric values

# The comma-separated string in braces is expanded
% array=(aa{bb,cc,11}) && echo $array
aabb aacc aa11

# ... expands the array before and after
% array=(aa{1..3}) && echo $array
aa1 aa2 aa3

# The second number is the interval of expansion.
% array=(aa{15..19..2}) && echo $array
aa15 aa17 aa19

# It can be expanded from large to small.
% array=(aa{19..15..2}) && echo $array
aa19 aa17 aa15

# You can add one or more leading zeros
% array=(aa{01..03}) && echo $array
aa01 aa02 aa03

# Single letters can also be expanded as numeric values, but multiple letters can't.
% array=(aa{a..c}) && echo $array
aaa aab aac

# The letters are expanded in the order of ASCII codes.
% array=(aa{Y..c}) && echo $array
aaY aaZ aa[ aa\ aa] aa^ aa_ aa` aaa aab aac


# These usages can be used in for loops
% for i (aa{a..c}) {
> echo $i
> }
aaa
aab
aac

Constructing arrays from strings

% str="a bb ccc dddd"

# ${= str} splits STR content into arrays by spaces
% array=(${=str})
% print -l $array[2,3]
bb
ccc


% str="a\nbb\nccc\ndddd"
# If you have other separators, you can specify them with (s:x:)
% array=(${(s:\n:)str})
% print -l $array[2,3]
bb
ccc


% str="a##bb##ccc##dddd"
# Separators can be multiple characters
% array=(${(s:##:)str})
% print -l $array[2,3]
bb
ccc


% str="a:bb:ccc:dddd"
# If the separator is:, you can (s.:.)
% array=(${(s.:.)str})
% print -l $array[2,3]
bb
ccc

Construct arrays from files

test.txt content.

a
bb
ccc
dddd

One element per line.

# The function of f is to separate strings into arrays with newline characters
# Double quotation marks can not be omitted, otherwise they will become a string, and quotation marks can also be added to ${}
% array=(${(f)"$(<test.txt)"})
% print -l $array
a
bb
ccc
dddd

# Effect without quotation marks
% array=(${(f)$(<test.txt)})
% print -l $array
a bb ccc dddd


# Construct arrays from files and output all columns by separator: after separating
for i (${(f)"$(<test.txt)"}) {
    array=(${(s.:.)i})
    echo $array[1,-1]
}

Constructing arrays from file lists

# The * here is the wildcard character mentioned in the previous article. All usages can be used here.
% array=(/usr/bin/vim*)
% print -l $array
/usr/bin/vim
/usr/bin/vimdiff
/usr/bin/vimtutor

# Much faster than ls/usr/bin/[a-b]?| wc-l
% array=(/usr/bin/[a-b]??) && print $#array
3

Array intersection difference set

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

# The intersection of two arrays, which only outputs elements that both arrays have
% echo ${array1:*array2}
1 2

# The difference set of two arrays outputs only the elements in array1 and not in array2.
% echo ${array1:|array2}
3

# If there are repetitive elements, they will not be duplicated.
% array1=(1 1 2 3 3)
% array2=(4 4 1 1 2 2)
% echo ${array1:*array2}
1 1 2

Array crossover merge

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

# Take one from array1, one from array2, and so on. When an array is finished, it ends.
% echo ${array1:^array2}
a 1 b 2 c 3

# If you use: ^, only one array is finished, continue to fetch from scratch until the second array is finished.
% echo ${array1:^^array2}
a 1 b 2 c 3 d 1

Unified processing of strings in arrays

Some methods dealing with strings (mainly various forms of interception, substitution, conversion, etc.) can also be used on arrays. The effect is to treat all elements in arrays in a unified way.

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

# t is the name of a file in a string. It can be used on an array to get the name of all elements.
% print -l ${array:t}
b.htm
c
c.txt

# e is an extension. If there is no extension, no empty string will be added to the result array.
% print -l ${array:e}
htm
txt

# String substitution and other operations can also be used for arrays, replacing all strings.
% print -l ${array/a/j}
/j/b.txt
/j/c
/j/b/c.txt

:# can also be used on arrays, but it's more practical.

% array=(aaa bbb ccc)

# :# It excludes matching elements, similar to grep-v
% print ${array:#a*}
bbb ccc

# The front plus (M) is the effect of reversing the back, that is, only the matched elements are output, similar to grep.
% print ${(M)array:#a*}
aaa

# Multiple operations can be performed simultaneously, (U) is to convert strings to uppercase letters
% print ${(UM)array:#a*}
AAA

summary

This article talks about the basic usage of arrays, there are many complex methods of operation, will be mentioned later.

Reference resources

http://zshwiki.org/home/scripting/array

http://www.bash2zsh.com/zsh_refcard/refcard.pdf

Update history

20170830: Add "Construct Arrays Using Continuous Characters or Numbers".

20170909: Correct the error in "Constructing arrays from strings".

This article is no longer updated. The whole series of articles are updated and maintained here. github.com/goreliu/zshguide

Tags: vim less ascii github

Posted on Fri, 24 May 2019 13:59:15 -0400 by lc