Fish has a utility for string maniplulation.
This is how you can do the same things with Zsh builtins.
References:
Get the length of a string with #
.
This is similar to string length
in fish.
$ str="abcdefghijklmnopqrstuvwxyz"
$ echo ${#str}
26
$
Left pad a string with the l expansion flag.
Right pad a string with the r expansion flag.
This is similar to string pad
in fish.
$ str="abc"
$ echo ${(l(10)(-))str}
-------abc
$ echo ${(r(10)(ABC))str}
abcABCABCA
$
The docs can be confusing. They show the syntax as l:expr::string1::string2:
, which
uses colons instead of the more readable parens. Don't be confused by the double colon,
which is really just the closing/opening combo )(
. If you choose to follow the docs,
the syntax looks like this:
$ str="abc"
$ echo ${(r:10::-:)str}
abc-------
$
Trim requires the use of sed
. This is similar to string trim
in fish.
$ str=" \t\t\t abc \t\t\t "
$ echo "$str" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
abc
$
Trimming strings other than whitespace can be accomplished with the '#' and '%' parameter expansions.
#
removes at the start of the string. #
is the shortest match, and ##
is the longest.
$ str="a/b/c/d/e/f/g"
$ echo ${str#*/}
b/c/d/e/f/g
$ echo ${str##*/}
g
$
%
removes at the end of the string. %
is the shortest match, and %%
is the longest.
$ str="a/b/c/d/e/f/g"
$ echo ${str%/*}
a/b/c/d/e/f
$ echo ${str%%/*}
a
$
Get a substing from string with comma indexing [start,end]
.
This is similar to string sub
in fish.
$ str="abcdefghijklmnopqrstuvwxyz"
$ echo ${str[3,6]}
cdef
$
You can also use the ${var:offset:length}
syntax:
$ str="abcdefghijklmnopqrstuvwxyz"
$ echo ${str:3:6}
defghi
$ echo ${str:(-4)}
wxyz
$
Repeat a string by using printf
.
This is similar to string repeat
in fish.
$ str="abc"
$ abc3=$(printf "$str%.0s" {1..3})
$ echo $abc3
abcabcabc
$
Escape (quote) strings with the q modifier.
This is similar to string escape
in fish.
$ str="3 tabs \t\t\t."
$ echo "${str:q}"
3\ tabs\ \t\t\t.
$
Unescape (unquote) strings with the Q modifier.
This is similar to string unescape
in fish.
$ str="3 backticks \`\`\`."
$ esc="${str:q}"
$ echo $esc
3\ backticks\ \`\`\`.
$ echo "${esc:Q}"
3 backticks ```.
$
Join strings with the j expansion flag.
This is similar to string join
in fish.
$ words=(abc def ghi)
$ sep=:
$ echo ${(pj.$sep.)words}
abc:def:ghi
$
A common join seperator is the null character.
This is similar to string join0
in fish.
$ words=(abc def ghi)
$ sep="\x00"
$ echo ${${(pj.$sep.)words}:q}
abc\x00def\x00ghi
$
Split strings with the s expansion flag.
This is similar to string split
in fish.
@
: Preserves empty elements. "In double quotes, array elements are put into separate words".p
: Use print syntax. "Recognize the same escape sequences as the print."s
: Split. "Force field splitting at the separator string."
$ str="a:b::c"
$ sep=:
$ printf '%s\n' "${(@ps.$sep.)str}"
a
b
c
$
A common split seperator is the null character.
This is similar to string split0
in fish.
$ str="abc\x00def\x00ghi"
$ sep="\x00"
$ arr=(${(ps.$sep.)str})
$ printf '%s\n' $arr
abc
def
ghi
$
Convert a string to uppercase with the u modifier.
This is similar to string upper
in fish.
$ str="AbCdEfGhIjKlMnOpQrStUvWxYz"
$ echo "${str:u}"
ABCDEFGHIJKLMNOPQRSTUVWXYZ
$
Convert a string to lowercase with the l modifier.
This is similar to string lower
in fish.
$ str="AbCdEfGhIjKlMnOpQrStUvWxYz"
$ echo "${str:l}"
abcdefghijklmnopqrstuvwxyz
$
The zsh/pcre
module allows you to match strings in Zsh.
$ zmodload zsh/pcre
$ str="The following are zip codes: 78884 90210 99513"
$ setopt REMATCH_PCRE
$ [[ $str =~ '\d{5}' ]] && echo "contains zips" || echo "no zips"
contains zips
$
$ zmodload zsh/pcre
$ str="https://gist.github.com/mattmc3/110eca74a876154c842423471b8e5cbb"
$ pattern='^(ftp|https?)://'
$ pcre_compile -smx $pattern
$ pcre_match -b -- $str
$ [[ $? -eq 0 ]] && echo "match: $MATCH, position: $ZPCRE_OP" || echo "no match"
match: https://, position: 0 8
$
Replacing leverages the s modifier. 'g' Means globally.
$ url=https://github.com/zsh-users/zsh-autosuggestions.git
$ url=${url%.git}
$ url=${url:gs/\@/-AT-}
$ url=${url:gs/\:/-COLON-}
$ url=${url:gs/\//-SLASH-}
$ echo $url
https-COLON--SLASH--SLASH-github.com-SLASH-zsh-users-SLASH-zsh-autosuggestions
$
There are lots of different ways strings need collected. Sometimes you have a string with embedded newlines that you need to split into an array, preserving blanks.
$ str=$(printf '%s\n' four score '' "&" '' seven years ago)
$ echo ${(q-)str}
'four
score
&
seven
years
ago'
$ # remove blanks
$ arr=(${(f@)str})
$ echo $#arr
6
$ # preserve blanks
$ arr=("${(f@)str}")
$ echo $#arr
8
$
This file passes clitests:
zsh -f -- =clitest --list-run --progress dot --color always zsh-strings.md
In zsh, you must use
$''
instead of""
to embed null characters in a string literal; see 5.1.3 POSIX quotes. The double quotes shown above will literally include the four characters "\x00" in the string.You can also put the \0 directly in the expansion flag, or use the short form
(0)
.