# Bash / Bash Script
## Waht is Shell
A **Shell** is a command interpreter.
Commands can be executable files or built-ins.
## What is Shell Script
A **Shell Script** is a plain text file containing a set of various commands.
It can be used to automate repetitive tasks on Linux filesystem.
## What is Bash
Bash is a common and popular shell.
## shebang
``` bash
#!/bin/bash
```
Specify the location of the shell interpreter in our operating system.
- on the first line
- no any space
## echo
``` bash
echo [option] [string]
```
Display the standard output by passing the arguments.
## Comment
### Single Line Comment
``` bash
# This is a single-line comment in Bash Script.
```
### Multi Line Comment
``` bash
<<COMMENTS
COMMENTS
: '
'
<<COMMENTS
This is a
multi-line comment
in Bash Script.
COMMENTS
: '
This is also a
multi-line comment
in Bash Script.
'
```
## Quote
Used to handle texts and filenames with a space character.
- content within the quotes should be considered as a single item
- shell variable expansion will only work with double-quotes.
``` bash
#!/bin/bash
name="asdf"
echo "$name"
echo '$name'
```
> asdf
> $name
## Variable
``` bash
name=Joey
echo $name
```
The containers which store data.
- case sensitive
- untyped
- no need of using any quotes to define a variable with single character value
- no whitespace when doing assignment
### System-Defined Variables
``` bash
echo $HOME
echo $PWD
```
- BASH - shell name
- BASH_VERSION - shell version
- HOME - home directory
- PWD - current working directory
## Command Line Arguments
```
./script.sh arg1 arg2 arg3
```
- $0 - the name of the script
- $1~$9 - the first 9 arguments
- $# - number of arguments
- $* - all arguments (as one word)
- $@ - all arguments (as array)
``` bash
echo $1 $2
```
## Command Substitution
``` bash
var=$(command_name)
echo $var
var=`command_name`
echo $var
```
It takes the output of the Bash command, stores in a variable, and display back with echo.
## Read User Input
``` bash
read variable_name
read -p "name:" variable_name # same prompt
read -sp "passward:" variable_name # silent mode
read -a array_name # read an array
```
## Arithmetic Operations
``` bash
Sum=$((10 + 3))
((Sum=10 + 3))
```
### Operators
- \+
- \-
- \*
- \/
- \*\*
- \%
- \+=
- \-=
- \*=
- \/=
- \%=
### Let
Perform arithmetic operations
```
let "z=$((10 + 3))"
```
### Backticks
Similar to "let", but it does not save the result to a variable.
``` bash
`expr $a + $b`
```
## If
```
test condition
[condition]
[[condition]]
```
``` bash
if [ condition ]
then
statements
fi
if [ condition ];
then
statements
else
statements
fi
if [ condition ];
then
statements
elif [ condition ];
then
statements
else
statements
fi
```
### Operators
- !EXPRESSION - check if EXPRESSION is false
- \-n STRING - check if the length of STRING is greater than zero
- \-z STRING - check if the length of STRING is zero
- STRING1 == STRING2
- STRING1 != STRING2
- INTEGER1 -eq INTEGER2
- INTEGER1 -gt INTEGER2
- INTEGER1 -ge INTEGER2
- INTEGER1 -lt INTEGER2
- INTEGER1 -le INTEGER2
- \-d FILE - check if FILE exists and it is a directory
- \-e FILE - check if FILE exists
## Case
``` bash
case expression in
pattern_1)
statements
;;
pattern_2)
statements
;;
pattern_3|pattern_4|pattern_5)
statements
;;
pattern-n)
statements
;;
*)
statements
;;
esac
```
## Loop
### For
``` bash
for variable in list
do
statements
done
for (( expression1; expression2; expression3 ))
do
statements
done
```
### While
``` bash
while [ expressions ];
do
commands
done
```
### Until
``` bash
until [ expressions ];
do
commands
done
```
## String
### Operator
- str1 = str2
- str1 != str2
- str1 < str2 (less than)
- str1 > str2 (greater than)
- -n str (length > 0)
- -z str (length == 0)
- ${#str} (return length)
## Pattern Matching
### Wildcard
- \* - match zero or more characters
- ? - match any single character
- [...] - match any of the characters in a set
- ?(patterns) - match zero or one occurrences of the patterns
- \*(patterns) - match zero or more occurrences of the patterns
- +(patterns) - match one or more occurrences of the patterns
- @(patterns) - match one occurrence of the patterns
- !(patterns) - match anything that doesn't match one of the patterns
### Curly braces
``` bash
# cat log.txt log.csv
cat log.{txt,csv}
# cat all *.py and *.sh files
cat *{.py,.sh}
```
## Substitution
- ${foo%suffix} - remove suffix
- ${foo#prefix} - remove prefix
- ${foo%%suffix} - remove long suffix
- ${foo##prefix} - remove long prefix
- ${foo/from/to} - replace first match
- ${foo//from/to} - replace all
- ${foo/%from/to} - replace suffix
- ${foo/#from/to} - replace prefix
## Function
``` bash
# Definition
function_name ()
{
statements
}
# Calling
function_name
```
### Passing Arguments
``` bash
# Calling with arguments
function_name ()
{
echo $1
echo $2
echo $3
}
function_name arg1 arg2 arg3
```
### Variable Scope
- variables are defined as global variables by default
``` bash
local name=Joey
```
## Array
### Initialization
``` bash
arr[0] = value_0
arr[1] = value_1
arr[2] = value_2
```
``` bash
arr=(value_0 value_1 value_2)
```
### Array Length
``` bash
${#arr[@]}
```
### Loop through the Array
``` bash
for ele in ${arr[@]}
do
echo $ele
done
for i in ${!arr[@]}
do
echo $i ":" ${arr[$i]}
done
```
### Adding Element
``` bash
arr+=(value)
```
### Remove Element
``` bash
unset arr[index]
```
### Delete Array
``` bash
unset arr
```
### Slice Array
``` bash
arr_slice=(${arr[@]:m:n})
```
### Check If Files Exist
``` bash
FILE=/etc/resolv.conf
if [-f "$FILE"]; then
echo "$FILE exists."
fi
```
- \-d FILE: True if the FILE exists and is a directory.
- \-e FILE: True if the FILE exists and is a file, regardless of type (node, directory, socket, etc.).
- \-f FILE: True if the FILE exists and is a regular file (not a directory or device).
- \-x FILE: True if the FILE exists and is executable.
### Stdio Redirection
- \>: redirect output (default 1>)
- \<: redirect input (default 0<)
- 0: stdin
- 1: stdout
- 2: stderr
- &>: 2>&1
``` bash
# redirect the stderr to file
command 2> file
# '> file' redirect the stdout to file
# then '2>&1' redirect the stderr to stdout.
command > file 2>&1
# redirect both stdout/stderr to file
command &> file
command 2>&1 > file
```
### Piping
redirect the stdout of the former program as the stdin of the latter program
``` bash
# count the number of particular files
ls *.txt | grep test | wc -l
# sort the content of a file
$ cat file.txt | sort | cat > sortedFile.txt
# read the specific line of a file
cat file.txt | head -3 | tail -1
```
#### xargs
execute a command using STDIN as arguments.
``` bash
# list all contents of files in the current dir
ls | xargs cat
```