```bash
#!/usr/bin/env bash
-NAME="John"
-echo "Hello $NAME!"
+name="John"
+echo "Hello $name!"
```
### Variables
```bash
-NAME="John"
-echo $NAME
-echo "$NAME"
-echo "${NAME}!"
+name="John"
+echo $name # see below
+echo "$name"
+echo "${name}!"
+```
+Generally quote your variables unless they contain wildcards to expand or command fragments.
+
+```bash
+wildcard="*.txt"
+option="iv"
+cp -$options $wildcard /tmp
```
### String quotes
```bash
-NAME="John"
-echo "Hi $NAME" #=> Hi John
-echo 'Hi $NAME' #=> Hi $NAME
+name="John"
+echo "Hi $name" #=> Hi John
+echo 'Hi $name' #=> Hi $name
```
### Shell execution
```bash
echo "I'm in $(pwd)"
-echo "I'm in `pwd`"
+echo "I'm in `pwd`" # obsolescent
# Same
```
```bash
name="John"
-echo ${name}
-echo ${name/J/j} #=> "john" (substitution)
-echo ${name:0:2} #=> "Jo" (slicing)
-echo ${name::2} #=> "Jo" (slicing)
-echo ${name::-1} #=> "Joh" (slicing)
-echo ${name:(-1)} #=> "n" (slicing from right)
-echo ${name:(-2):1} #=> "h" (slicing from right)
-echo ${food:-Cake} #=> $food or "Cake"
+echo "${name}"
+echo "${name/J/j}" #=> "john" (substitution)
+echo "${name:0:2}" #=> "Jo" (slicing)
+echo "${name::2}" #=> "Jo" (slicing)
+echo "${name::-1}" #=> "Joh" (slicing)
+echo "${name:(-1)}" #=> "n" (slicing from right)
+echo "${name:(-2):1}" #=> "h" (slicing from right)
+echo "${food:-Cake}" #=> $food or "Cake"
```
```bash
length=2
-echo ${name:0:length} #=> "Jo"
+echo "${name:0:length}" #=> "Jo"
```
See: [Parameter expansion](http://wiki.bash-hackers.org/syntax/pe)
```bash
-STR="/path/to/foo.cpp"
-echo ${STR%.cpp} # /path/to/foo
-echo ${STR%.cpp}.o # /path/to/foo.o
-echo ${STR%/*} # /path/to
+str="/path/to/foo.cpp"
+echo "${str%.cpp}" # /path/to/foo
+echo "${str%.cpp}.o" # /path/to/foo.o
+echo "${str%/*}" # /path/to
-echo ${STR##*.} # cpp (extension)
-echo ${STR##*/} # foo.cpp (basepath)
+echo "${str##*.}" # cpp (extension)
+echo "${str##*/}" # foo.cpp (basepath)
-echo ${STR#*/} # path/to/foo.cpp
-echo ${STR##*/} # foo.cpp
+echo "${str#*/}" # path/to/foo.cpp
+echo "${str##*/}" # foo.cpp
-echo ${STR/foo/bar} # /path/to/bar.cpp
+echo "${str/foo/bar}" # /path/to/bar.cpp
```
```bash
-STR="Hello world"
-echo ${STR:6:5} # "world"
-echo ${STR: -5:5} # "world"
+str="Hello world"
+echo "${str:6:5}" # "world"
+echo "${str: -5:5}" # "world"
```
```bash
-SRC="/path/to/foo.cpp"
-BASE=${SRC##*/} #=> "foo.cpp" (basepath)
-DIR=${SRC%$BASE} #=> "/path/to/" (dirpath)
+src="/path/to/foo.cpp"
+base=${src##*/} #=> "foo.cpp" (basepath)
+dir=${src%$base} #=> "/path/to/" (dirpath)
```
### Substitution
| Code | Description |
| ----------------- | ------------------- |
-| `${FOO%suffix}` | Remove suffix |
-| `${FOO#prefix}` | Remove prefix |
+| `${foo%suffix}` | Remove suffix |
+| `${foo#prefix}` | Remove prefix |
| --- | --- |
-| `${FOO%%suffix}` | Remove long suffix |
-| `${FOO##prefix}` | Remove long 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 first match |
+| `${foo//from/to}` | Replace all |
| --- | --- |
-| `${FOO/%from/to}` | Replace suffix |
-| `${FOO/#from/to}` | Replace prefix |
+| `${foo/%from/to}` | Replace suffix |
+| `${foo/#from/to}` | Replace prefix |
### Comments
| Expression | Description |
| --------------- | ------------------------------ |
-| `${FOO:0:3}` | Substring _(position, length)_ |
-| `${FOO:(-3):3}` | Substring from the right |
+| `${foo:0:3}` | Substring _(position, length)_ |
+| `${foo:(-3):3}` | Substring from the right |
### Length
| Expression | Description |
| ---------- | ---------------- |
-| `${#FOO}` | Length of `$FOO` |
+| `${#foo}` | Length of `$foo` |
### Manipulation
```bash
-STR="HELLO WORLD!"
-echo ${STR,} #=> "hELLO WORLD!" (lowercase 1st letter)
-echo ${STR,,} #=> "hello world!" (all lowercase)
+str="HELLO WORLD!"
+echo "${str,}" #=> "hELLO WORLD!" (lowercase 1st letter)
+echo "${str,,}" #=> "hello world!" (all lowercase)
-STR="hello world!"
-echo ${STR^} #=> "Hello world!" (uppercase 1st letter)
-echo ${STR^^} #=> "HELLO WORLD!" (all uppercase)
+str="hello world!"
+echo "${str^}" #=> "Hello world!" (uppercase 1st letter)
+echo "${str^^}" #=> "HELLO WORLD!" (all uppercase)
```
### Default values
| Expression | Description |
| ----------------- | -------------------------------------------------------- |
-| `${FOO:-val}` | `$FOO`, or `val` if unset (or null) |
-| `${FOO:=val}` | Set `$FOO` to `val` if unset (or null) |
-| `${FOO:+val}` | `val` if `$FOO` is set (and not null) |
-| `${FOO:?message}` | Show error message and exit if `$FOO` is unset (or null) |
+| `${foo:-val}` | `$foo`, or `val` if unset (or null) |
+| `${foo:=val}` | Set `$foo` to `val` if unset (or null) |
+| `${foo:+val}` | `val` if `$foo` is set (and not null) |
+| `${foo:?message}` | Show error message and exit if `$foo` is unset (or null) |
-Omitting the `:` removes the (non)nullity checks, e.g. `${FOO-val}` expands to `val` if unset otherwise `$FOO`.
+Omitting the `:` removes the (non)nullity checks, e.g. `${foo-val}` expands to `val` if unset otherwise `$foo`.
Loops
-----
```bash
for i in /etc/rc.*; do
- echo $i
+ echo "$i"
done
```
```bash
for ((i = 0 ; i < 100 ; i++)); do
- echo $i
+ echo "$i"
done
```
### Reading lines
```bash
-cat file.txt | while read line; do
- echo $line
-done
+while read -r line; do
+ echo "$line"
+done <file.txt
```
### Forever
```bash
myfunc() {
local myresult='some value'
- echo $myresult
+ echo "$myresult"
}
```
```bash
-result="$(myfunc)"
+result=$(myfunc)
```
### Raising errors
### Working with arrays
```bash
-echo ${Fruits[0]} # Element #0
-echo ${Fruits[-1]} # Last element
-echo ${Fruits[@]} # All elements, space-separated
-echo ${#Fruits[@]} # Number of elements
-echo ${#Fruits} # String length of the 1st element
-echo ${#Fruits[3]} # String length of the Nth element
-echo ${Fruits[@]:3:2} # Range (from position 3, length 2)
-echo ${!Fruits[@]} # Keys of all elements, space-separated
+echo "${Fruits[0]}" # Element #0
+echo "${Fruits[-1]}" # Last element
+echo "${Fruits[@]}" # All elements, space-separated
+echo "${#Fruits[@]}" # Number of elements
+echo "${#Fruits}" # String length of the 1st element
+echo "${#Fruits[3]}" # String length of the Nth element
+echo "${Fruits[@]:3:2}" # Range (from position 3, length 2)
+echo "${!Fruits[@]}" # Keys of all elements, space-separated
```
### Operations
```bash
Fruits=("${Fruits[@]}" "Watermelon") # Push
Fruits+=('Watermelon') # Also Push
-Fruits=( ${Fruits[@]/Ap*/} ) # Remove by regex match
+Fruits=( "${Fruits[@]/Ap*/}" ) # Remove by regex match
unset Fruits[2] # Remove one item
Fruits=("${Fruits[@]}") # Duplicate
Fruits=("${Fruits[@]}" "${Veggies[@]}") # Concatenate
```bash
for i in "${arrayName[@]}"; do
- echo $i
+ echo "$i"
done
```
### Working with dictionaries
```bash
-echo ${sounds[dog]} # Dog's sound
-echo ${sounds[@]} # All values
-echo ${!sounds[@]} # All keys
-echo ${#sounds[@]} # Number of elements
-unset sounds[dog] # Delete dog
+echo "${sounds[dog]}" # Dog's sound
+echo "${sounds[@]}" # All values
+echo "${!sounds[@]}" # All keys
+echo "${#sounds[@]}" # Number of elements
+unset sounds[dog] # Delete dog
```
### Iteration
```bash
for val in "${sounds[@]}"; do
- echo $val
+ echo "$val"
done
```
```bash
for key in "${!sounds[@]}"; do
- echo $key
+ echo "$key"
done
```
### Redirection
```bash
-python hello.py > output.txt # stdout to (file)
-python hello.py >> output.txt # stdout to (file), append
-python hello.py 2> error.log # stderr to (file)
-python hello.py 2>&1 # stderr to stdout
-python hello.py 2>/dev/null # stderr to (null)
-python hello.py &>/dev/null # stdout and stderr to (null)
+python hello.py > output.txt # stdout to (file)
+python hello.py >> output.txt # stdout to (file), append
+python hello.py 2> error.log # stderr to (file)
+python hello.py 2>&1 # stderr to stdout
+python hello.py 2>/dev/null # stderr to (null)
+python hello.py >output.txt 2>&1 # stdout and stderr to (file), equivalent to &>
+python hello.py &>/dev/null # stdout and stderr to (null)
+echo "$0: warning: too many users" >&2 # print diagnostic message to stderr
```
```bash
printf "This is how you print a float: %f" 2
#=> "This is how you print a float: 2.000000"
+
+printf '%s\n' '#!/bin/bash' 'echo hello' >file
+# format string is applied to each group of arguments
+printf '%i+%i=%i\n' 1 2 3 4 5 9
```
### Transform strings
#### Example
```bash
-echo "Welcome To Devhints" | tr [:lower:] [:upper:]
+echo "Welcome To Devhints" | tr '[:lower:]' '[:upper:]'
WELCOME TO DEVHINTS
```
### Directory of script
```bash
-DIR="${0%/*}"
+dir=${0%/*}
```
### Getting options
```bash
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
-V | --version )
- echo $version
+ echo "$version"
exit
;;
-s | --string )
```bash
echo -n "Proceed? [y/n]: "
-read ans
-echo $ans
+read -r ans
+echo "$ans"
```
+The `-r` option disables a peculiar legacy behavior with backslashes.
+
```bash
read -n 1 ans # Just one character
```