notes/IT/Scripting.md

146 lines
8.5 KiB
Markdown
Raw Permalink Normal View History

2024-05-30 18:01:43 +00:00
## Marking a script as executable
2024-05-30 18:02:43 +00:00
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`
2024-05-30 18:01:43 +00:00
2024-05-30 23:46:46 +00:00
## The Shebang
2024-05-30 18:02:43 +00:00
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:
2024-05-30 18:00:43 +00:00
```sh
#!/bin/sh
echo "Hello, World!"
2024-05-30 23:43:28 +00:00
```
2024-05-30 23:45:46 +00:00
`#!/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.
2024-05-30 23:46:46 +00:00
## Variables
2024-05-30 23:48:46 +00:00
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
2024-05-30 23:49:46 +00:00
# There may not be any spaces used during assignment, `A = B` means something different than `A=B`
2024-05-30 23:48:46 +00:00
# Assignment is done with the equal sign (=) operator:
2024-05-30 23:49:46 +00:00
MY_VARIABLE="Hi Mom!"
echo $MY_VARIABLE
2024-05-30 23:50:46 +00:00
```
2024-05-30 23:52:46 +00:00
## Quotes
2024-05-31 00:02:46 +00:00
In Bash, different styles of quotes (or a backtick) mean different things:
2024-05-30 23:52:46 +00:00
2024-05-31 00:03:46 +00:00
| 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>``` |
2024-05-31 00:05:46 +00:00
| 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>``` |
2024-05-31 00:06:46 +00:00
## Conditionals
2024-05-31 00:07:46 +00:00
A basic if statement in bash looks like this:
2024-05-31 00:15:46 +00:00
```bash
2024-05-31 00:07:46 +00:00
if somecommand; then
2024-05-31 00:08:46 +00:00
# The code here will be run if somecommand has an exit code of 0
2024-05-31 00:07:46 +00:00
fi
```
2024-05-31 00:08:46 +00:00
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.
2024-05-31 00:09:46 +00:00
2024-05-31 00:15:46 +00:00
You can also make use of `else` or `elif` for more complex conditional logic:
```bash
2024-05-31 00:09:46 +00:00
if somecommand; then
2024-05-31 00:10:46 +00:00
# If the command succeeds, run this code
2024-05-31 00:09:46 +00:00
else
2024-05-31 00:10:46 +00:00
# If the command fails, run this code.
2024-05-31 00:09:46 +00:00
fi
```
2024-05-31 00:15:46 +00:00
`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
```
2024-05-31 00:09:46 +00:00
2024-05-31 00:17:46 +00:00
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
```
2024-05-31 00:27:46 +00:00
If using `test` or the shorthand of test (`[]`), there are a variety of binary comparison operators you can make use of:
2024-05-31 00:30:46 +00:00
| 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 |
2024-05-31 00:31:46 +00:00
The above list is far from complete but it contains some of the more commonly used operators
2024-05-31 00:22:46 +00:00
## 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"
2024-05-31 00:23:46 +00:00
for THING in $THINGS; do
echo "Doing something to $THING"
2024-05-31 00:22:46 +00:00
done
```
2024-05-31 00:24:46 +00:00
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
```
2024-05-31 00:25:46 +00:00
### While loops
`while` loops operate on lists of unknown size. It will keep running until the `test` it evaluates returns false:
2024-05-31 00:26:46 +00:00
```bash
i=0
while [ $i -lt 10 ]; do
echo $i
i=$(( $i + 1))
done
echo “Done counting”
```
2024-05-31 00:31:46 +00:00
## Functions
2024-05-31 00:32:46 +00:00
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"
}
```
2024-05-31 00:22:46 +00:00
2024-05-31 00:33:46 +00:00
To execute a function, simply include the name of the function. To execute the above function:
```bash
function_name
```
2024-05-31 00:34:46 +00:00
By default, all variables in bash are global. To declare a local variable in a function, prefix the declaration with the `local` keyword.
2024-05-31 00:33:46 +00:00
```bash
function_name () {
2024-05-31 00:34:46 +00:00
local A='A'
echo `A`
2024-05-31 00:33:46 +00:00
}
```
2024-05-31 00:35:46 +00:00
To return a value from a function, use the `return` keyword. After calling, it'll be assigned to the global variable `$?`.
2024-05-31 00:37:47 +00:00
```bash
my_function () {
return 55
}
2024-05-31 00:35:46 +00:00
2024-05-31 00:37:47 +00:00
my_function
# Will echo 55
echo $?
2024-05-31 00:36:46 +00:00
```
2024-05-30 23:51:46 +00:00
## Commands
2024-05-31 00:12:46 +00:00
| 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: `[]` |