Scripting & Functions

The goal of cicada is to be a useful daily-use shell and replace Bash. It does not intend to compete with shells like zsh, fish, etc. Cicada keeps KISS Principle in mind. For scripting, cicada won't introduce a full featured scripting language as bash did. For complex scripting job, I would recommend you to use bash (and call them with $ bash xxx.sh in cicada), or dynamic scripting languages like Python. Scripting with cicada should only be used in simple cases.

Introduction

Firstly, cicada supports run commands (or pipes) line by line from a file:

File content of ~/hello.sh:

#!/usr/local/bin/cicada
echo hello scripting
# spliting command into multiple lines
echo hi \
      there
echo "the args are: $@"
echo $3 $1 $2
date
echo bye

We can make this file as executable with:

$ chmod +x ~/hello.sh

Then there are two methods to run it:

a) Run it directly

$ ~/hello.sh foo bar baz

b) Pass it to cicada

$ cicada ~/hello.sh foo bar baz

Either way, the output looks like this:

hello scripting
hi there
runing /home/mitnk/hello.sh with args: foo bar baz
baz foo bar
Sat Apr 27 17:14:36 CST 2019
bye

If Statements

In every if statement, each test conditions are checked one by one, and run cmds in first True condition. True conditions means the commands that exit with status 0.

if echo foo | grep -iq o
    echo found foo
fi

if echo foo | grep -iq bar
    echo found bar
else
    echo not found bar
fi

if echo foo | grep -iq a
    echo found a
else if echo foo | grep -iq b
    echo found b
else
    echo no a and no b
fi

The output of above script is:

found foo
not found bar
no a and no b

Use test [ command

The test command [ is a convenient tool to use in if and while statements.

foo=35
if [ $foo -gt 10 ]
    echo "foo is great than 10"
else
    echo "foo is less than 10"
fi

if [ $(uname -s) = 'Darwin' ]
    echo "you're using Mac OS"
fi

For for details, please check out [ --help (or man test) in your shell.

Note: Compare strings with [ $str1 > $str2 ] is not supported in cicada. The > would be treated as output redirections.

For Statements

In cicada, for statement loop the space splitted strings. In each iteration, the string is assigned to the variable, and run commands with this just available variable.

for var in foo bar baz
    echo $var
done

for var2 in $(echo a b)
    echo hello && echo $var2
done

for var3 in 'args kwargs' "sh script"
    echo $var3
done

for f in src/builtins/ex*.rs
    echo source file $f
done

for x in {1..10..2}
    echo "x = $x"
done

The output of above script is:

foo
bar
baz

hello
a
hello
b

args kwargs
sh script

source file src/builtins/exec.rs
source file src/builtins/exit.rs
source file src/builtins/export.rs

x = 1
x = 3
x = 5
x = 7
x = 9

While Statements

In while statements, the command body will be run whenever the test branch is still true.

counter=17
while echo "$counter" | grep -iq "^1.$"
    echo "counter = $counter"
    counter=$(expr $counter + 1)
done

The output is:

counter = 17
counter = 18
counter = 19

Combine If, For, While Together

As expected, you can combine/nested the above statements together.

One example is set ls aliases in RC-file:

if which exa > /dev/null
    alias ls='exa'
    alias ll='exa -lh --time-style=long-iso'
else
    if uname -s | grep -iq 'darwin'
        alias ls='ls -G'
        alias ll='ls -Glh'
    else
        alias ls='ls --color=auto'
        alias ll='ls -lh --color=auto'
    fi
fi

Another example:

counter=17
if echo foo | grep -q oo
    while echo "$counter" | grep -iq "^1.$"
        echo "counter = $counter"
        counter=$(expr $counter + 1)
    done
fi

if echo foo | grep -q oo
    if echo bar | grep -q oo
        echo found oo
    else
        while echo "$counter" | grep -iq "^2[0-2]$"
            echo "counter = $counter"
            counter=$(expr $counter + 1)
        done
    fi
fi

The output is:

counter = 17
counter = 18
counter = 19

counter = 20
counter = 21
counter = 22

The source Builtin

See also the source builtin.

Command like $ cicada foo.sh would create a new session and run the commands of file foo.sh. If you want to run them in current shell session, you can run it with $ source foo.sh.

Using Builtins

In scripts, you could also use cicada's builtins. For example, you can include extra configs with source at the end of RC file: (RC file itself is a valid cicada script).

# content of my rc-file

alias ll='ls -lh'

...  # other configs

# include some extra settings for this host only at the end
source ~/.cicadarc_local

Functions

A function is defined like this:

function <function-name>() {
    <function-body>
}

NOTE: The function <function-name>() { and } part must be in its own line. The () part is optional.

One example:

$ cat bar.sh
function foo-bar() {
    echo hi
    echo $0
    echo $1 $2
    echo bye
}

After define it, you can call it in the same file (bar.sh) like this:

foo-bar arg1 arg2

Another way is you can source this file and run this function in the shell:

$ source bar.sh
$ foo-bar arg1 arg2 arg3

The output would be:

hi
foo-bar
arg1 arg2
bye