Zsh Development Guide (Chapter 8 Variable Modifiers)

Posted by sssphp on Thu, 23 May 2019 22:09:56 +0200

Guide reading

We have learned the basic usage of strings, arrays, hash tables, integers, floating-point numbers, but we are still unable to cope with some complex scenarios.

Variable modifier is a very unique concept in zsh. It operates on variables with functions similar to functions, but it is more convenient to use. Complex functions in a line of code mainly depend on it. And the price is worse readability, how to use it has to be weighed. It is also one of the most distinctive parts of zsh. Variable modifiers are mainly used in arrays and hash tables, but a small part can also be applied to strings (integers and floating-point numbers are also treated as strings).

The Format of Variable Modifiers

In fact, in the previous articles, variable modifiers have appeared, but at that time there was no detailed description.

For example, in the case of case conversion.

% str="ABCDE abcde"

# To capitalize, (U) and: u have the same effect.
% echo ${(U)str} --- ${str:u}
ABCDE ABCDE --- ABCDE ABCDE

# Converting to lowercase, (L) and: l works the same way
% echo ${(L)str} --- ${str:l}
abcde abcde --- abcde abcde

Here (U),: l and so on are variable modifiers. Variable modifiers have two main forms.

${(x)var}
${var:x}

Among them, VaR is the variable name and x is one or more letters. Different letters have different functions. The colon in the second line may also be another symbol. The ${var} and $VaR are basically the same, and braces are used to avoid the character in the variable name and the character behind it, usually without increasing brackets. However, if variable modifiers are used, braces are essential (in fact, braces can be omitted in the second format, but it is better to add them considering readability and error hints, etc.).

Variable modifiers can be nested. Because the variables with modifiers are still variables, they can be treated as normal variables.

% str=abc
% echo ${(U)str}
ABC
% echo ${(C)${(U)str}}
Abc

% echo ${${a:u}:l}
abc

# Two styles can be nested together
% echo ${(C)${a:u}}
Abc

It's important to note that there should be no blanks after $or there will be grammatical errors. That is to say, we can't avoid the readability deterioration caused by character crowding by adding spaces. But when you are familiar with the format, you can easily recognize the function of the code. Complicated logic can be written on new lines without necessarily being nested.

After knowing the usage of variable modifiers, it is important to know which variable modifiers can be used.

Default value of variable

Variables can be of any type related to the default value of a variable (the default value used if the variable is empty or does not exist when reading it).

% var=123

# If a variable has a value, it outputs the value of the variable.
% echo ${var:-abc}
123

# If the variable has no value (the variable does not exist, it is an empty string, an empty array, an empty hash table, etc.), output abc
% echo ${varr:-abc}
abc


% var=""
# And: - Similar, but only if the variable does not exist will it be replaced by the default value
% echo ${var-abc}
% echo ${varr-abc}
abc


% var=""
# And: - Similar, but if the variable has no value, it is assigned abc.
% echo ${var:=abc}
abc
% echo $var
abc


% var=abc
# Whether var has a value or not, it is assigned a value of 123.
% echo ${var::=123}
123
% echo $var
123


% var=""
# If var has no value, report the error directly
% echo ${var:?error}
zsh: var: error


% var=abc
# If var has a value, output 123
% echo ${var:+123}
% echo ${varr:+123}

Array splicing into strings

% array=(aa bb cc dd)

# Stitching with line breaks
% echo ${(F)array}
aa
bb
cc
dd

# Stitching with Spaces
% str=$array
% echo $str
aa bb cc dd

# Stitching with other characters or strings
% echo ${(j:-=:)array}
aa-=bb-=cc-=dd

String splitting into arrays

% str=a##b##c##d

% array=(${(s:##:)str})
% print -l $array
a
b
c
d

Output variable type

# Note that if you don't add integer or float, they are all strings, but the type is automatically converted when calculating
% integer i=1
% float f=1.2
% str=abc
% array=(a b c)
% local -A hashmap=(k1 v1 k2 v2)

% echo ${(t)i} ${(t)f} ${(t)str} ${(t)array} ${(t)hashmap}
integer float scalar array association

String, array, or hash table nested values

Multiple layers can be nested.

% str=abcde
% echo ${${str[3,5]}[3]}
e

% array=(aa bb cc dd)
% echo ${${array[2,3]}[2]}
cc
# If there is only one element left, take the character of the string
% echo ${${array[2]}[2]}
b

% local -A hashmap=(k1 v1 k2 v2 k3 v3)
% echo ${${hashmap[k1]}[2]}
1

String content is revalued as variable name

There is no need to do this through tedious eval.

% var=abc
% abc=123

% echo ${(P)var}
123

Align or truncate strings in an array

% array=(abc bcde cdefg defghi)

# Take only the last two characters of each string
% echo ${(l:2:)array}
bc de fg hi

# Complete strings with spaces and align them right
% print -l ${(l:7:)array}
    abc
   bcde
  cdefg
 defghi

# Completion with specified characters
% print -l ${(l:7::0:)array}
0000abc
000bcde
00cdefg
0defghi

# Complete with the specified character and use the second character only once
% print -l ${(l:7::0::1:)array}
0001abc
001bcde
01cdefg
1defghi

# Left alignment
% print -l ${(r:7::0::1:)array}
abc1000
bcde100
cdefg10
defghi1

summary

In this paper, only a few variable modifiers are introduced, and some are not mentioned, which may be supplemented later.

Reference resources

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

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

Topics: github