# 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](https://en.wikipedia.org/wiki/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](#user-content-introduction) - [If Statements](#user-content-if-statements) - [For Statements](#user-content-for-statements) - [While Statements](#user-content-while-statements) - [Using Builtins](#user-content-using-builtins) - [Functions](#user-content-functions) ## Introduction Firstly, cicada supports run commands (or pipes) line by line from a file: File content of `~/hello.sh`: ```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`. ```sh 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](https://linux.die.net/man/1/test) command `[` is a convenient tool to use in `if` and `while` statements. ```sh 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. ```sh 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. ```sh 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](https://github.com/mitnk/cicada/blob/master/docs/rc-file.md): ```sh 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: ```sh 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](https://github.com/mitnk/cicada/blob/master/docs/builtins.md#user-content-source). 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](https://github.com/mitnk/cicada/blob/master/docs/builtins.md). For example, you can include extra configs with `source` at the end of [RC file](https://github.com/mitnk/cicada/blob/master/docs/rc-file.md): (RC file itself is a valid cicada script). ```sh # 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: ```txt function () { } ``` **NOTE:** The `function () {` 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 ```