## Ako písať dobré bash skripty
miroslav.binas@tuke.sk / [**OSS Conf 2018**](http://ossconf.soit.sk/)
## Miesto agendy
* nie som nadšený _bash ~~striptér~~ skriptér_
* sú situácie, kedy sa použitie `bash`-u vyslovene nehodí
* je to však fantastický nástroj na prepájanie rozličných riešení
* _glue_
* _swiss army knife_ každého _DevOps_-áka
* nasledujúci zoznam odporúčaní nie je kompletný
## #1 Nezabúdajte na prenositeľnosť!
### Prenositeľný _Hello world!_
```bash
#!/usr/bin/env bash
echo "Hello world!"
```
* `env` - run a program in a modified environment
* ak je parametrom príkaz, nájde prvú binárku v premennej `PATH` a spustí ju
* spoľah na umiestnenie `/usr/bin/env`
## #2 Pri výskyte chyby sa musí skript zastaviť!
### Zlý skript
```bash
#!/usr/bin/env bash
echo "start here"
VAR = "syntax error on this line"
echo "this line will be executed too"
```
### Začnite takto
```bash
#!/usr/bin/env bash
set -o errexit # stop when error occurs
set -o pipefail # if not, expressions like `error here | true`
# will always succeed
set -o nounset # detects uninitialised variables
set -o xtrace # prints every expression
# before executing it (debugging)
echo "start here"
VAR = "syntax error on this line"
echo "this line is now not reachable"
```
## #3 Uzatvárajte premenné do `"${variable}"`
* _escaping_
* úvodzovky pomôžu pri premenných, ktoré obsahujú medzery
* zložené zátvorky nie sú úplne potrebné, ale používajú sa pri tzv. _bash expansion_
* interpolácia reťazcov - `"${variable}.yml"`
* predvolená (fallback) hodnota - `"${variable:-something_else}"`
* náhrada reťazcov - `"${variable//from/to}"`
## #4 Používajte `[[ ]]` miesto `[ ]`
(`[[` - rozšírenie bash-u, `[` - skrátený zápis príkazu `test`)
### Mocné vychytávky
* premenné netreba uzatvárať do úvodzoviek
```bash
[[ -f ${file} ]] # vs. [ -f "${file}" ]
```
* podporuje operátory `&&` a `||` a porovnávanie reťazcov pomocou operátorov `<` a `>`
* zaviedol operátor `=~` pre porovnávanie na základe regulárnych výrazov
```bash
[[ ${answer} =~ ^y(es)?$ ]]
```
* podporuje _globbing_
```bash
[[ ${answer} = y* ]]
```
## #5 Píšte skripty modulárne
* miesto písania všetkého do jedného súboru ho uložte do viacerých (modulov)
* jednoduchšia údržba a navigácia
* logicky uzavretá (a oddelená) funkcionalita
* vkladanie/rozšírenie existujúceho skriptu o nový docielite príkazom `source`
```bash
# ...
source "${DATADIR}/helper.sh"
# ...
```
## #6 Nepoužívajte nástroje, ktorých funkcie `bash` zvláda
* jedna z najčastejších (nevedomých) chýb
* najčastejšie `grep`, `awk`, `sed`, `bc`, `expr`, napr.:
```bash
size=$(du -hs images/ | awk '{print $1}')
```
vyriešiť pomocou
```bash
array=($(du -hs images/))
size=${array[0]}
```
* namiesto `seq 1 10` použite `{1..10}`
* používajte `$()` miesto ``
## #7 Píšte skripty tak, aby sa dali testovať
* "mocný" prístup - všetko uzavrieť do funkcie
```bash
#!/usr/bin/env bash
main(){
echo "Hello world!"
}
main
```
* existuje mnoho nástrojov pre podporu testovania v bash-i (napr. [bats](https://github.com/sstephenson/bats))
```bash
#!/usr/bin/env bats
@test "when new folder is created, then exit status is 0" {
run mkdir "${dir}"
assert_equal "${status}" 0
}
```
> **Linter** je program, ktorý skontroluje kód na prítomnosť _programátorských_ a _štýlových_ chýb, čím pomáha zvýšiť kvalitu kódu.
### [ShellCheck](https://www.shellcheck.net/)
* Shell script analysis tool
* obsahuje tzv. [galériu zlého kódu](https://github.com/koalaman/shellcheck/blob/master/README.md#user-content-gallery-of-bad-code), ktorá vám ukáže, čo všetko vám môže `ShellCheck` pomôcť identifikovať
* nachádza sa vo vašej distribúcii
## Ostatné odporúčania
* deklarácia konštánt
```bash
readonly var='immutable value'
```
* písanie vlastných funkcií
```bash
_greetings(){
local name="$1"
printf "%s\n" "${name}"
}
```
![qr code](https://api.qrserver.com/v1/create-qr-code/?data=http://bit.ly/2ku8ZO6&size=300x300)
(**http://bit.ly/2ku8ZO6**)