Preface
Goal: Exploring Ion Shell for string processing.
The ion
shell from redox-os
,
has been in my radar since years ago.
But this is the first time I experience this modern shell.
The syntax is concise, powerfull.
I can wait patiently for redox-os
to be happened.
And for you all developer who work silently in the background.
Keep the good job!
Reference Reading
Source Examples
You can obtain source examples here:
Common Use Case
Task: Get the unique tag string
Please read overview for more detail.
Data Structure Support
Unlike like bash
, fish
or any other shell,
ion
support array in array.
But it is not easy to access.
Slo decide to use plain string
instead.
For learning purpose,
we can explore fish
capability,
with CSV like data.
Prepopulated Data
Songs and Poetry
The data is simply an array containing multilines. Which each lines separated by semicolon, then separated by comma.
#!/usr/bin/env ion
let songs:[str] = [\
"Cantaloupe Island;60s,jazz" \
"Let It Be;60s,rock" \
"Knockin' on Heaven's Door;70s,rock" \
"Emotion;70s,pop" \
"The River"
]
Ion Solution
The Answer
ion
shell differ scalar variable and array variable.
This makes the shell easier to return array variable.
#!/usr/bin/env ion
source ./MySongs.sh
source ./MyHelperFlatten.sh
# Extract flatten output to array
let tags_fl = $(flatten [@songs])
let tags_un = $(echo $tags_fl | sort -u)
echo $join(@split($tags_un \n) :)
Enough with introduction, at this point we should go straight to coding.
Environment
Normally, ion
shell is not available in repository.
In my artix linux, I can get ion-git
shell from aur,
where in other distribution,
I have to compile the ion
shell manually.
1: Array in Ion shell
I decide to use plain data,
instead of associative array
.
Although plain data only consist of lines of string, we still have to examine a bit about array.
Simple Array
Consider begin with simple array
.
#!/usr/bin/env ion
let tags:[str] = ["rock" "jazz" "rock" "pop" "pop"]
echo @tags
echo @tags[1]
With output result as below:
❯ ./01-tags.sh
rock jazz rock pop pop
jazz
Associative Array
Although we won’t use associative array
.
We can examine a bit.
Now consider this form.
#!/usr/bin/env ion
let song:hmap[str] = [ \
title='Cantaloupe Island' \
tags=["60s" "jazz"] \
]
echo @song
echo @song[title]
echo @song[tags]
let tags = @song[tags]
let tags = [ @split($tags) ]
echo @tags[1]
With output result as below:
❯ ./02-map.sh
tags 60s jazz title Cantaloupe Island
Cantaloupe Island
60s jazz
jazz
We still have no problem with code above. But unfortunately we cannot go further than this.
Using String Join Command
consider go straight with plain data.
We can test join
command.
See the command in action.
And examine how the command works.
#!/usr/bin/env ion
let songs = [\
"Cantaloupe Island;60s,jazz" \
"Let It Be;60s,rock" \
"Knockin' on Heaven's Door;70s,rock" \
"Emotion;70s,pop" \
"The River"
]
echo $join(@songs \n)
With the result, similar as below record:
❯ ./03-songs.sh
Cantaloupe Island;60s,jazz
Let It Be;60s,rock
Knockin on Heavens Door;70s,rock
Emotion;70s,pop
The River
No need complex structure.
2: Separating Module
Since we need to reuse the songs record multiple times, it is a good idea to separate the record structure from logic.
Songs Module
The code is pretty similar with above code, as shown as below:
#!/usr/bin/env ion
let songs:[str] = [\
"Cantaloupe Island;60s,jazz" \
"Let It Be;60s,rock" \
"Knockin' on Heaven's Door;70s,rock" \
"Emotion;70s,pop" \
"The River"
]
Using Songs Module
Now we can have a very short code. With the result exactly the same as above code:
#!/usr/bin/env ion
source ./MySongs.sh
echo $join(@songs \n)
Or alternatively, we can alter the output, using read and loop.
#!/usr/bin/env ion
source ./MySongs.sh
for song in @songs
let pair = [@split($song ;)]
if test $len(@pair) -gt 1
echo "@pair[0] is [@pair[1]]"
end
end
With the result as below lines of string
.
❯ ./04-module-b.sh
Cantaloupe Island is [60s,jazz]
Let It Be is [60s,rock]
Knockin on Heavens Door is [70s,rock]
Emotion is [70s,pop]
Notice how the split
command has delimiter ;
option.
let pair = [@split($song ;)]
This split
command,
read variables based on,
the this delimiter value.
3: Finishing The Task
Extract, Flatten, Unique
Extracting Data Structure
Based on the result above,
we can go further, extracting the tags
data.
#!/usr/bin/env ion
source ./MySongs.sh
let tagss = []
for song in @songs
let pair = [@split($song ;)]
if test $len(@pair) -gt 1
let tagss ++= @pair[1]
end
end
echo $join(@tagss ":")
With the result of array
of array
, as shown below.
❯ ./05-extract.sh
60s,jazz:60s,rock:70s,rock:70s,pop
Notice how we populate the tagss
array variable,
by append value for each loop.
let tagss ++= @pair[1]
Flatten
Now we can normalize, the separated values. Flatten all values into just single array.
Using two loops. One after another.
#!/usr/bin/env ion
source ./MySongs.sh
let tagss = []
let tags = []
for song_item in @songs
let pair = [@split($song_item ;)]
if test $len(@pair) -gt 1
let tagss ++= @pair[1]
end
end
for tags_item in @tagss
let tag_temp = [@split($tags_item ,)]
let tags ++= [@tag_temp]
end
echo $join(@tags ":")
With the result of a flattened array
shown below.
❯ ./06-flatten-a.sh
60s:jazz:60s:rock:70s:rock:70s:pop
I know it is a little bit long. This long code looks inefficient. We are going to make the code shorter.
Flatten Rewrite
We can rewrite above statement, using loop in a loop, to make the code shorter.
#!/usr/bin/env ion
source ./MySongs.sh
let tags = []
for song_item in @songs
let pair = [@split($song_item ;)]
if test $len(@pair) -gt 1
let tags ++= [@split(@pair[1] ,)]
end
end
echo $join(@tags ":")
With the result exactly the same as previous flattened array
.
Flatten Function
Since we are going to reuse the flatten approach above in other code. It is better to bundle the script in its own module.
#!/usr/bin/env ion
fn flatten songs:[str]
let tags = []
for song_item in @songs
let pair = [@split($song_item ;)]
if test $len(@pair) -gt 1
let tags ++= [@split(@pair[1] ,)]
end
end
echo $join(@tags \n)
end
Again, pay attention to the return values.
Returning array in ion
shell is,
simply with echo $join()
command.
Now we can use code above in other script.
Unique
Instead of solving the approach using pure ion
,
I prefer to use sort -u
instead.
#!/usr/bin/env ion
source ./MySongs.sh
source ./MyHelperFlatten.sh
# Extract flatten output to array
flatten [@songs] | sort -u
With the result similar as below array:
❯ ./07-unique-a.sh
60s
70s
jazz
pop
rock
We still need to join this array. Now have a look at this code below:
I have to put the pipe in two lines to make it works.
#!/usr/bin/env ion
source ./MySongs.sh
source ./MyHelperFlatten.sh
# Extract flatten output to array
let tags_fl = $(flatten [@songs])
let tags_un = $(echo $tags_fl | sort -u)
echo $join(@split($tags_un \n) :)
With the result similar as below array:
❯ ./07-unique-b.sh
60s:70s:jazz:pop:rock
It is nice to know something rare such as ion
shell.
What is Next 🤔?
Consider continue reading [ Ion Shell - Playing with Records - Part Two ].