%title: Bash Scripting: It's not so bad %author: Cody Hiar %date: 2019-05-27 -> Bash Scripting: It's not so bad <- ===================================== ------------------------------------------------- # About Me * Graduated Computer Engineering at U of A * SaltStack Certified * Now working remotely @ Blendable * Vim/Tmux Diehard, also cli in general * Interests: Python, Automation, DevOps, Linux # Where I be * www.codyhiar.com * www.github.com/thornycrackers # Past Presentations (available on GitHub) * Scraping with scrapy (YEGSEC) * Python Daemons (Edmonton.py) * Setting Django up on a VPS (Edmonton.py) * Docker (YEGSEC) ------------------------------------------------- -> Goals <- =========== - What's in the Language - Some best practices - Resources to help ------------------------------------------------- -> Why bash scripting? <- ========================= - Easy win with tools you already have install. - Scripts are easy to share between different people. - I don't like repeating myself ^ -> When to bash script: <- ===================== ^ - Everyday. Automate everything. Invaluable for quick throw away scenarios. Scripting is a great way to learn how linux/unix systems in general work. ^ -> When not to bash script: <- ========================= ^ - Personal Take: If your script is getting past the 100ish line mark it's probably a good time to consider moving to a different language ------------------------------------------------- -> Bash has it's own language <- ================================ Bash has support for a bunch of the basic programming features you need such as: Variables, Functions, If/Else, Conditionals, Loops, Arrays, Dictionaries, Case Switch. ------------------------------------------------- # Variables ``` NAME="John" ``` # Functions ``` get_name() { echo "John" } echo "You are $(get_name)" ``` # If/Else ``` if [[ -z "$string" ]]; then echo "String is empty" elif [[ -n "$string" ]]; then echo "String is not empty" fi ``` ------------------------------------------------- # Conditionals ``` git commit && git push git commit || echo "Commit failed" ``` # For Loop ``` for i in {1..5}; do echo "Welcome $i" done ``` # While Loop ``` while true; do ยทยทยท done ``` ------------------------------------------------- -> The "while" poem <- ====================== While true do foo sleep 1 done ``` while true; do clear; curl https://duckduckgo.com; sleep 1; done ``` ------------------------------------------------- # Array ``` Fruits=('Apple' 'Banana' 'Orange') echo ${Fruits[0]} ``` # Dictionaries ``` declare -A sounds sounds[dog]="bark" echo "${sounds[dog]}" ``` # Case Switch ``` case "$1" in start | up) vagrant up ;; *) echo "Usage: $0 {start|stop|ssh}" ;; esac ``` ------------------------------------------------- -> My First Bash Script <- ========================== 1. Run: `touch myscript.sh` 2. Add the following content ``` #!/usr/bin/env bash echo "Hello World" ``` 3. Run: `chmod +x myscript.sh` 4. Run: `./myscript.sh` ------------------------------------------------- -> What can I put in a shell script <- ====================================== Anything you type into your terminal to run commands can be put into a bash script. This means that Bash Scripts are essentially a free way to start automating things that you do on a daily basis without having to install any new tools. ------------------------------------------------- -> Example: Postgres Backup <- ================================ ``` #!/usr/bin/env bash TODAY=$(date +%F) FILENAME="database_backup-${TODAY}.sql" if [[ ! -f "$FILENAME" ]]; then pg_dump -h hostname -U myuser > "$FILENAME" fi ``` ------------------------------------------------- -> Best Practice: Idempotence <- ================================ Plain English: Output or effect is the same if a script is ran multiple times. ^ This isn't limited to Bash Scripting but is a good practice in other DevOps tools you may be using as well. ------------------------------------------------- -> Best Practice: Unofficial Strict Mode <- =========================================== ``` #!/usr/bin/env bash # # Set options: # e: Stop script if command fails # u: Stop script if unset variable is referenced # x: Debug, print commands as they are executed # o pipefail: If any command in a pipeline fails it all fails # # IFS: Internal Field Separator set -euxo pipefail IFS=$'\\n\\t' ``` ------------------------------------------------- -> Best Practice: Traps <- ========================== ``` #!/usr/bin/env bash function finish { # Your cleanup code here } trap finish EXIT ``` Traps are the equivalent of wrapping your script in a giant `try/catch` statement so that if anything does fail, the script will clean up after itself. ------------------------------------------------- -> Best Practice: Linting with Shellcheck <- ============================================ The goals of ShellCheck are To point out and clarify typical beginner's syntax issues that cause a shell to give cryptic error messages. To point out and clarify typical intermediate level semantic problems that cause a shell to behave strangely and counter-intuitively. To point out subtle caveats, corner cases and pitfalls that may cause an advanced user's otherwise working script to fail under future circumstances. https://github.com/koalaman/shellcheck ------------------------------------------------- -> Best Practice: Automated testing with bats-core <- ===================================================== Bats is a TAP-compliant testing framework for Bash. It provides a simple way to verify that the UNIX programs you write behave as expected. https://github.com/bats-core/bats-core ------------------------------------------------- -> Resources <- =============== - https://explainshell.com/ - https://misc.flogisoft.com/bash/tip_colors_and_formatting - https://www.bash.academy/ - http://redsymbol.net/articles/bash-exit-traps/ - http://redsymbol.net/articles/unofficial-bash-strict-mode/ - https://devhints.io/bash - https://github.com/jlevy/the-art-of-command-line - https://google.github.io/styleguide/shell.xml - http://www.bashoneliners.com/ - https://www.commandlinefu.com - https://www.codyhiar.com/snippets/awesome-bookmarks-my-collection/ ------------------------------------------------- -> Questions <- ===============