## Marking a script as executable Sometimes, you may need to mark a script as an executable to run it. On Linux, this can be accomplished by `chmod +x [FILE]`, where `[FILE]` is the file you want to mark as executable. To unmark a file as executable, use `chmod -x` ## The Shebang There are various shells with their own language syntax (`sh`, `bash`, `fish`, etc). Therefore, more complicated scripts will indicate a particular shell by specifying the absolute path to the interpreter as the first line, prefixed by `#!` like this: ```sh #!/bin/sh echo "Hello, World!" ``` `#!/bin/sh` means that this script can be executed by the binary located at `/bin/sh`, and so the reader knows this is a `sh`(ell) script. ## Variables In bash, variable assignment is done with the `=` operator. Variables are conventionally named with `SCREAMING_SNAKE_CASE`, and can be accessed by prefixing the variable name with a dollar sign (`$`): ```bash #!/bin/bash # There may not be any spaces used during assignment, `A = B` means something different than `A=B` # Assignment is done with the equal sign (=) operator: MY_VARIABLE="Hi Mom!" echo $MY_VARIABLE ``` ## Quotes In Bash, different styles of quotes (or a backtick) mean different things: | Quote | Description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Single Quotes (') | Enclosing characters in single quotes (`'`) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash. Commands in single quotes will not be evaluated. | | Double Quotes (") | Enclosing characters in double quotes (`"`) preserves the literal value of all characters within the quotes, with the exception of `$`, \`, `\`, and, when history expansion is enabled, `!`. The characters `$` and \‘ retain their special meaning within double quotes. A double quote may be quoted within double quotes by preceding it with a backslash. When the shell is in POSIX mode (see Bash POSIX Mode), the ‘!’ has no special meaning within double quotes, even when history expansion is enabled.<br><br>Within double quotes, substitution can be done using `$()`.<br><br>```<br>"Output of ls: $(ls)"<br>``` | | Backtick (\`) | While a backtick is not technically a quotation mark, it's included here. Backticks are used to substitute the output a command in a location:<br>```<br>sudo chown `id -u` /some/directory<br>``` | ## Conditionals A basic if statement in bash looks like this: ```bash if somecommand; then # The code here will be run if somecommand has an exit code of 0 fi ``` Note that the if statement is terminated by `fi`. This is fairly standard throughout bash scripting, where the blocks are closed with the reverse text used to open them. You can also make use of `else` or `elif` for more complex conditional logic: ```bash if somecommand; then # If the command succeeds, run this code else # If the command fails, run this code. fi ``` `elif`: ```bash if [ "$1" = "hello" ]; then echo "hello yourself" elif [ "$1" = "goodbye" ]; then echo "nice to have met you" echo "I hope to see you again" else echo "I didn't understand that" fi ``` To test one value against a variety of conditions, you can use `case`: ```bash case "$1" in hello|hi) echo "hello yourself" ;; goodbye) echo "nice to have met you" echo "I hope to see you again" ;; *) echo "I didn't understand that" esac ``` If using `test` or the shorthand of test (`[]`), there are a variety of binary comparison operators you can make use of: | Operator | Description | | -------- | --------------------------- | | `-eq` | Is equal to | | `-ne` | Is not equal to | | `-gt` | Is greater than | | `-ge` | Is greater than or equal to | | `-lt` | Is less than | | `-le` | Is less than or equal to | The above list is far from complete but it contains some of the more commonly used operators ## Loops ### For loops `for` loops are used when you have a finite collection over which you want to iterate, such as a list of files, or a list of server names: ```bash THINGS="thingone thingtwo thingthree" for THING in $THINGS; do echo "Doing something to $THING" done ``` The above example iterates over a space separated list of items, but if you wanted to iterate over a range of numbers, you could do something like this: ```bash for i in {1..10} ; do ... ; done ``` ### While loops `while` loops operate on lists of unknown size. It will keep running until the `test` it evaluates returns false: ```bash i=0 while [ $i -lt 10 ]; do echo $i i=$(( $i + 1)) done echo “Done counting” ``` ## Functions While there are a few ways to declare a function in bash, the most common syntax looks like this: ```bash function_name () { echo "I was called by a function" } ``` To execute a function, simply include the name of the function. To execute the above function: ```bash function_name ``` By default, all variables in bash are global. To declare a local variable in a function, prefix the declaration with the `local` keyword. ```bash function_name () { local A='A' echo `A` } ``` To return a value from a function, use the `return` keyword. After calling, it'll be assigned to the global variable `$?`. ```bash my_function () { return 55 } my_function # Will echo 55 echo $? ``` ## Commands | Command | Description | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `exit [CODE]` | Make the script process exit, where `[CODE]` is the exit code the process will terminate with. | | `read [VARIABLE]` | Read user input into the provided variable. | | `test [CONDITION]` | Used for conditionals, `test` will return an exit code of 0 if the test evaluates to true. Refer to the [manual](https://man7.org/linux/man-pages/man1/test.1.html) for more info. As a shorthand, you can enclose the condition in square brackets: `[]` |