Preface
Goal: Exploring Fish Shell for string processing.
Bash is great, but I really think bash is so legacy. And I wonder why we can not obtain better shell approach. This riddle has been a long time in mhy mind, but I haven’t got time to examine fish shell in real life.
So here I am. Porting my bash
script into fish
script.
I found that, the fish
script is tidier,
than the bash
counterpart.
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
Just like bash
or any other shell,
fish
does not support multidimensional array.
And it also doesn’t support array in array.
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 fish
set songs \
"Cantaloupe Island;60s,jazz" \
"Let It Be;60s,rock" \
"Knockin' on Heaven's Door;70s,rock" \
"Emotion;70s,pop" \
"The River"
FISH Solution
The Answer
Instead of IFS
, we are going to use string join
command,
to extract variable in fish
.
This approach saved a few lines. Ans easier to read the script.
#!/usr/bin/env fish
source ./MySongs.sh
source ./MyHelperFlatten.sh
# Extract flatten output to array
set tags (flatten $songs | sort -u)
string join ':' $tags
Enough with introduction, at this point we should go straight to coding.
Environment
No need any special setup. Just run and voila..!
1: Array in FISH
I decide to use plain data,
instead of associative array
.
Although plain data only consist of lines of string, we still have to examine array, a bit.
Simple Array
Consider begin with simple array
.
#!/usr/bin/env fish
set tags "rock" "jazz" "rock" "pop" "pop"
echo $tags
With output result as below:
❯ ./01-tags.sh
rock jazz rock pop pop
We won’t discuss about associative array
.
Since I decide not to use data structure approach.
Using String Join Command
consider go straight with plain data.
We can test string join
command.
See the command in action.
And examine how the command works.
#!/usr/bin/env fish
set songs \
"Cantaloupe Island;60s,jazz" \
"Let It Be;60s,rock" \
"Knockin' on Heaven's Door;70s,rock" \
"Emotion;70s,pop" \
"The River"
string join \n\b $songs
With the result, similar as below record:
❯ ./03-songs.sh
Cantaloupe Island;60s,jazz
Let It Be;60s,rock
Knockin' on Heaven's 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 fish
set songs \
"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 fish
source ./MySongs.sh
string join \n\b $songs
Or alternatively, we can alter the output, using read and loop.
#!/usr/bin/env fish
source ./MySongs.sh
for song in $songs
echo $song | read -d ';' title tags
echo "$title is $tags"
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 Heaven's Door is 70s,rock
Emotion is 70s,pop
The River is
Notice how the read
command has delimiter option.
echo $song | read -d ';' title tags
This read
command,
split 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 fish
source ./MySongs.sh
set -l tagss
for song in $songs
echo $song | read -d ';' title tags
set -a tagss $tags
end
string 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.
set -a tagss $tags
Flatten
Now we can normalize, the separated values. Flatten all values into just single array.
Using two loops. One after another.
#!/usr/bin/env fish
source ./MySongs.sh
set -l tagss
set -l tags
for song_item in $songs
echo $song_item | read -d ';' title tags
set -a tagss $tags
end
for tags_item in $tagss
echo $tags_item | read -d ',' -a tag_temp
set -a tags $tag_temp
end
string join ':' $tagss
string join ':' $tags
With the result of a flattened array
shown below.
❯ ./06-flatten-a.sh
60s,jazz:60s,rock:70s,rock:70s,pop
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 fish
source ./MySongs.sh
set -l tags
for song_item in $songs
echo $song_item | read -d ';' title tags_temp
for tags_item in $tags_temp
echo $tags_item | read -d ',' -a tag_temp
set -a tags $tag_temp
end
end
string 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 fish
function flatten
set -l l_songs $argv
set -l tags
for song_item in $l_songs
echo $song_item | read -d ';' title tags_temp
for tags_item in $tags_temp
echo $tags_item | read -d ',' -a tag_temp
set -a tags $tag_temp
end
end
string join \n $tags
end
Now, pay attention to the return values.
Returning array in fish
is,
simply with string join
command.
Now we can use code above in other script.
Unique
Instead of solving the approach using pure fish
,
I prefer to use sort -u
instead.
#!/usr/bin/env fish
source ./MySongs.sh
source ./MyHelperFlatten.sh
# Extract flatten output to array
set tags (flatten $songs | sort -u)
string join ':' $tags
With the result similar as below array:
❯ ./07-unique.sh
60s:70s:jazz:pop:rock
I don’t want to be perfect,
or fish purist.
I just want to know a little about fish
.
What is Next 🤔?
Consider continue reading [ Fish Shell - Playing with Records - Part Two ].