├── example ├── db-backup └── user-add └── README.md /example/db-backup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #This script will create a directory 3 | #and postgres database backup with current 4 | #time file name. Also it it will delete the oldest 5 | 6 | app="project" 7 | mkdir -p $HOME/db_backups/"$app"/ 8 | now=$(date +"%d-%m-%Y") 9 | filename="dump_$now" 10 | path=$HOME/db_backups/"$app"/"$filename" 11 | pg_dump --no-acl "$app"_production > "$path" 12 | find $HOME/db_backups/"$app" -mtime +10 -delete 13 | -------------------------------------------------------------------------------- /example/user-add: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script will add user 3 | # If user already exist it will throw an exception 4 | # You should run this as root 5 | 6 | if [ $(id -u) -eq 0 ]; then 7 | read -p "Enter username : " username 8 | read -s -p "Enter password : " password 9 | egrep "^$username" /etc/passwd > /dev/null 10 | if [ $? -eq 0 ]; then # Exception if user already exists 11 | echo "$username exists!" 12 | exit 1 13 | else 14 | pass=$(perl -e 'print crypt($ARGV[0], "password")' $password) # Passing password in encrypted form 15 | useradd -m -p $pass $username 16 | [ $? -eq 0 ] && echo "User has been added to system!" || echo "Failed to add a user!" 17 | fi 18 | else 19 | echo "Only root may add a user to the system" 20 | exit 2 21 | fi -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Best script practices 2 | 3 | ![Bash](https://cdn-images-1.medium.com/max/256/1*FEE98iWinlZBYkxBAG8MvA.png) 4 | 5 | [**Bash**](https://www.gnu.org/software/bash/) is an ideal systems language for UNIX or command line tasks. Of course, in some cases it's better to use systems languages like C or Go. However, Bash can solve almost all of your problems, you just need to use it. 6 | 7 | ## Basic Rules 8 | 9 | * It’s recommended to apply Clean Code principles while working with Bash. 10 | 11 | * All code blocks should be commented. Thus, it makes the script easier to read and understand. 12 | 13 | * Always double quote variables, including subshells. No naked `$` signs. 14 | 15 | ```bash 16 | echo "Names without double quotes" 17 | echo 18 | names="Codica Shell Practises" 19 | for name in $names; do 20 | echo "$name" 21 | done 22 | echo 23 | 24 | echo "Names with double quotes" 25 | echo 26 | for name in "$names"; do 27 | echo "$name" 28 | done 29 | ``` 30 | 31 | ## Variables 32 | 33 | * Variables is used to store your values. You should operate them carefully, because sometimes Bash sometimes can use undeclared variables. 34 | 35 | * Concerning variables, use names that reflect the values stored in them, but try to make it more briefly. 36 | 37 | * Make static variables read-only. 38 | 39 | ```bash 40 | # Password file variable 41 | readonly passwd_file='/etc/passwd' 42 | ``` 43 | 44 | * Always use local when setting variables, unless there is reason to use declare. 45 | 46 | * An exception to this are cases when you are intentionally setting a variable in an outer scope. 47 | 48 | ```bash 49 | func(){ 50 | cd $PWD 51 | } 52 | ``` 53 | 54 | ## Functions 55 | 56 | * Functions are created to reduce the amount of code. Try to write brief functions, that do only one task if it is possible. 57 | 58 | * Declare variables with a meaningful name for positional parameters of functions. 59 | 60 | * Use UNIX-like approach: a function does one thing. 61 | 62 | ```bash 63 | # Function description 64 | func(){ 65 | printf("Hello world!") 66 | } 67 | ``` 68 | 69 | ## I/O 70 | 71 | * Your script will sometimes require input from user. Try to make a clear message of your script requirements and don't forget to handle all correctly. 72 | 73 | * You should prefer `printf` to `echo`. 74 | 75 | * `printf` gives more control over the output, it’s more portable and its behaviour is defined better. 76 | 77 | * Your script should always react to abnormal input. 78 | 79 | ```bash 80 | func(){ 81 | echo -e "Unexpected argument!" 82 | } 83 | ``` 84 | 85 | * It should always return 0 in case of a success and another value otherwise. It would be great if you can handle those. 86 | 87 | * If your script requires user input, use prompts. 88 | 89 | ```bash 90 | printf "Input email: " 91 | read email 92 | printf "$email" 93 | ``` 94 | 95 | ![prompt](https://media.giphy.com/media/S9Ps0mDRJhTbT9hYxw/giphy.gif) 96 | 97 | ## Security 98 | 99 | * Security is very important thing. When writing a script be prepared for that your script will be executed by a less experienced person, so you should make your script fool-proof. 100 | 101 | * Don't store your credentials in shell scripts, people can have access to your script. Use `ENV` variables or [vaults](https://www.vaultproject.io/) instead. 102 | 103 | * You should always remember that your script can be executed on other machines or in container, so you need to use environment variables i.e. 104 | 105 | ```bash 106 | # Copying from remote machine with ENV path 107 | scp 192.168.0.1:$HOME $HOME 108 | ``` 109 | 110 | * Instead of 111 | 112 | ```bash 113 | # Copying from remote machine with an absolute path 114 | scp 192.168.0.1:/home/myuser /home/otheruser 115 | ``` 116 | 117 | * The matter is that there may not be those directories you want to copy. 118 | 119 | * Sometimes the script will be executed even when a command fails. Thus, will affect the rest of the script. Use `set -o errexit` exit a script when a command fails. 120 | 121 | * `nounset` flag to exit when your script tries to use undeclared variables. 122 | * `xtrace` helps to trace what gets executed (useful for debugging) 123 | 124 | ```bash 125 | #let the script exit if a command fails 126 | set -o errexit 127 | set -o nounset 128 | set -o xtrace 129 | ``` 130 | 131 | ## Useful Tips 132 | 133 | * You should prefer absolute paths `/home/user/file` instead to relative `~/file`. 134 | 135 | * Use `.sh` or `.bash` extension if the file is meant to be included/sourced. Don’t use these extensions on executable script. 136 | 137 | * Do not use deprecated style. 138 | 139 | * Define functions as `func() { }`. 140 | 141 | * Always use `[[...]]` instead of `[]`. 142 | 143 | * Do not use backticks, use `$( ... )`. 144 | 145 | ## License 146 | 147 | Best script practices is Copyright © 2015-2019 Codica. It is released under the [MIT License](https://opensource.org/licenses/MIT). 148 | 149 | ## About Codica 150 | 151 | [![Codica logo](https://www.codica.com/assets/images/logo/logo.svg)](https://www.codica.com) 152 | 153 | We love open source software! See [our other projects](https://github.com/codica2) or [hire us](https://www.codica.com/) to design, develop, and grow your product. --------------------------------------------------------------------------------