Skip to content

Commit 8dac561

Browse files
committed
Add zsh string split gist as a post
1 parent 24f6203 commit 8dac561

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
+++
2+
title = 'Zsh - splitting a string into an array'
3+
date = 20120-09-17T00:00:00-04:00
4+
categories = 'Guide'
5+
tags = ['Zsh', 'Shell']
6+
+++
7+
8+
There are a ton of different ways to split up a string in Zsh. This post attempts to
9+
show them with examples to help you build your own. I write Zsh scripts all the time,
10+
and still reference back to this guide, so there you go.
11+
12+
From the Zsh docs on [Parameter Expansion
13+
Flags](https://zsh.sourceforge.io/Doc/Release/Expansion.html#Parameter-Expansion-Flags)
14+
(yeah - I know... how would anyone ever find that if they didn't know where to look!?)
15+
16+
> j:string: Join the words of arrays together using string as a separator. s:string:
17+
> Force field splitting at the separator string.
18+
19+
You can also read more by running `man zshexpn`. (Again... I know, right!? How would
20+
anyone know to look there!?)
21+
22+
Example splitting a string on slash character in Zsh.
23+
24+
```zsh
25+
$ str=part1/part2/part3
26+
$ parts=(${(@s:/:)str})
27+
$ echo $parts
28+
part1 part2 part3
29+
$ echo ${#parts[@]}
30+
3
31+
```
32+
33+
You can use split `${(@s:/:)str}` and indexing `[start,end]` to do more sophisticated
34+
surgery on string parts. Note that Zsh array indexing starts a 1, not 0.
35+
36+
If you need to reassemble, simply join back on the same separator `${(@j:/:)str}`. Note:
37+
weirdly, the colons can be swapped out for other symbols, so if you prefer periods for
38+
example, this would also work: `${(@j./.)str}`. Since I'm splitting on slashes, I choose
39+
not to use slash as my symbol.
40+
41+
```zsh
42+
$ url="https://github.com/sorin-ionescu/prezto/blob/master/modules/history/init.zsh"
43+
$ repo="${(@j:/:)${(@s:/:)url}[4,5]}"
44+
$ echo $repo
45+
sorin-ionescu/prezto
46+
```
47+
48+
[An example from the Zsh
49+
docs](https://zsh.sourceforge.io/Doc/Release/Expansion.html#Examples) which shows
50+
splitting. Note the use of slash below unlike the colon above to surround the split
51+
character - remember that symbol is swapable and doesn't change the behavior of the
52+
split at all:
53+
54+
```zsh
55+
$ foo=(ax1 bx1)
56+
$ print -l -- ${(s/x/)foo}
57+
a
58+
1 b
59+
1
60+
```
61+
62+
Getting the first 2 parts
63+
64+
```zsh
65+
$ str=a/b/c/d/e/f
66+
$ parts=(${(@s:/:)str})
67+
$ echo ${(@j:/:)parts[1,2]}
68+
a/b
69+
```
70+
71+
You can also use `#` and `%` parameter expansion symbols: [see
72+
docs](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion). `#`
73+
removes from the left side, and `%` from the right, which I remember by the fact that
74+
`#` is to the left of `%` on your actual keyboard. `##` and `%%` use the longest match,
75+
while `#` and `%` use the shortest.
76+
77+
```zsh
78+
$ str=part1/part2/part3
79+
$ echo ${str%%/*}
80+
part1
81+
$ echo ${str%/*}
82+
part1/part2
83+
$ echo ${${str%/*}#*/}
84+
part2
85+
$ echo ${str#*/}
86+
part2/part3
87+
$ echo ${str##*/}
88+
part3
89+
```
90+
91+
Word splitting is done with the '=' character:
92+
93+
```zsh
94+
$ sentence="ls -l -A -h"
95+
$ arr=(${=sentence})
96+
$ print -l -- $arr
97+
ls
98+
-l
99+
-A
100+
-h
101+
```
102+
103+
Hope this is a helpful reference. There's [also a gist that I keep up-to-date as well
104+
here](https://gist.github.com/mattmc3/76ad634f362b5a9a54f1779a4737d5ae).

0 commit comments

Comments
 (0)