## 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.
Within double quotes, substitution can be done using `$()`.
```
"Output of ls: $(ls)"
``` |
| 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:
```
sudo chown `id -u` /some/directory
``` |
## 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: `[]` |