#!<Path to the executable that will run the script>
#!/bin/bash
#!/usr/bin/python
...
# Without a shebang
bash script.sh
# With a shebang
chmod +x script.sh
./script.sh
# "./" is important !
$(pwd) # Error: trying to execute the output of the pwd as a command
echo $(pwd) # Good: echo the result of the command as string
[ 25 -eq 20 ] # 25 est égal à 20 ?
echo $? # Retourne le résultat de la dernière commande
# 1 --> False
var1=17
var2=18
echo "$( [ $var1 -gt $var2 ]; echo $?)" # 1 --> False
echo "$(test $var1 -ne $var2 ; echo $?)" # 0 --> True
num1=5
num2=10
sum=$((num1 + num2)) # 15
difference=$((num2 - num1)) # 5
product=$((num1 * num2)) # 50
quotient=$((num2 / num1)) # 2
increment=$((num1++)) # 6
sleep 10 &
echo "I don't wait for sleep to finish"
echo "PID of the background process: $!"
mkdir mydir && cd mydir
# go to "mydir" only if created successfully
[ -f "config.yml" ] || echo "Missing config file"
echo "Step 1" ; false ; echo "Step 3"
ls | wc -l
# ls list the number of files and send the text result to wc (word count) that count the number of line (-l)
ps aux | grep firefox
# All firefox process
# Input <
sort < names.txt
# is equivalent to
cat names.txt | sort
# Output (Overwrite) > 1>
ls > files.txt
ls 1> files.txt
# Create empty file of emty it
> myfile.txt
# Output (Append) >>
echo "new entry" >> log.txt
# Redirect stderr
ls nonexistent 2> errors.txt
# Redirect to stderr and stdout to file
ls /etc /nonexistent > all.txt 2>&1
ls /etc /nonexistent &> all.txt # bash only
color=red
[ "$color" = "red" ] && { echo "Color is red"; } \
|| { [ "$color" = "blue" ] && { echo "Color is blue"; } \
|| echo "Color is something else"; }
# Option 1: Named function
my_function() {
echo "Hello from function"
}
# Option 2: Function keyword (optional style)
function my_function {
echo "Hello from function"
}
# Call the function
my_function
greet() {
echo "Hello, $1!"
echo "You passed $# arguments."
}
greet A B
# Hello, A!
# You passed 2 arguments.
add() {
echo $(( $1 + $2 ))
}
result=$(add 3 5)
echo "Result is $result"
# Result is 8
is_even() {
(( $1 % 2 == 0 )) && return 0 || return 1
}
if is_even 4; then
echo "Even"
else
echo "Odd"
fi
Variable are global by default
greet() {
local name=$1
echo "Hi, $name"
}
name="World"
echo "Hello, $name!"
greeting="Hello, "
name="World"
echo "$greeting$name"
# Hello, World
echo "$greeting Name" # "Hello, Name" <-- double space so not really good
echo "$greetingName" # "" <-- think that this i ona variable name
echo "${greeting}Name" # "Hello, Name" <-- Good !
# "${var}" let us disambiguate the variable name
number=42
echo "The number is $number"
num1=5
num2=10
sum=$((num1 + num2))
echo "The sum is $sum"
fruits=("apple" "banana" "cherry")
echo $fruits
# apple
echo ${fruits[@]}
# apple banana cherry
fruits[1]="peach"
# apple peach cherry
declare -A colors
colors[apple]="red"
colors[banana]="yellow"
colors[grape]="purple"
echo ${colors[apple]}
# red
echo ${colors[@]}
# purple red yellow
# Print function
printarr() { declare -n __p="$1"; for k in "${!__p[@]}"; do printf "%s=%s\n" "$k" "${__p[$k]}" ; done ; }
echo $colors
# grape=purple
# apple=red
# banana=yellow
Variable | Meaning | Example |
---|---|---|
$0 |
Name of the script | myscript.sh |
$1 to $9 |
First to ninth argument | $1 = "foo" |
${10} |
Tenth argument and beyond | ${10} , ${11} |
$# |
Number of arguments | 3 if 3 args were passed |
$@ |
All arguments as separate strings | Good for for arg in "$@" |
$* |
All arguments as a single string | One big string of all args |
Variable | Meaning |
---|---|
$? |
Exit status of the last command (0 = success) |
$$ |
PID (process ID) of the current script |
$! |
PID of the last backgrounded command (& ) |
$- |
Current shell options (e.g., himBH ) |
$_ |
Last argument of the previous command |
Variable | Meaning |
---|---|
$PWD |
Current working directory |
$OLDPWD |
Previous directory (used with cd - ) |
$UID |
Numeric user ID of the current user |
$EUID |
Effective user ID (important for root detection) |
$HOSTNAME |
Name of the machine |
$RANDOM |
Random number (0–32767) |
$SECONDS |
Seconds since shell started |
$LINENO |
Current line number in script |
$BASH_VERSION |
Bash version string |
Format : [ expr1 OP expr2 ] LOG-OP [ expr3 OP expr4 ]
OP :
-eq
:==
-ne
:!=
-gt
:>
-ge
:>=
-lt
:<
-le
:<=
LOG-OP (Logical Operator):
&&
:AND
||
:OR
!
:NOT
Test an operator
echo "$([ ... ]; echo $?)"
# 0 --> True
# 1 --> False
# $? output the result of the last command
if CONDITION
then
echo "Error"
fi
if CONDITION1
then
echo "Error"
elif CONDITION2 ; then
echo "Perfect"
else
echo "Ok"
fi
personnes="Kyâne Stéphane Quentin"
# for i in {1..10}
# for nom in "Kyâne" "Stéphane" "Quentin"
for nom in $personnes
do
echo "Bonjour $nom"
done
while CONDITION
do
read -p 'Dites "bonjour" : ' reponse
done
Pattern matching
file=img.jpg
case "$file" in
*.jpg) echo "It's a JPEG image." ;;
*.sh) echo "It's a shell script." ;;
*) echo "Unknown file type." ;;
esac
Logic in condition
day=$(date +%A)
case "$day" in
Monday|Tuesday|Wednesday|Thursday|Friday)
echo "Weekday" ;;
Saturday|Sunday)
echo "Weekend" ;;
esac
Multiple commands
read -p "Enter a number (1-3): " num
case "$num" in
1)
echo "You chose One"
echo "First is the best!"
;;
2)
echo "You chose Two"
echo "Second is still great."
;;
3)
echo "You chose Three"
echo "Third time’s the charm."
;;
*)
echo "Invalid choice"
echo "Please enter 1, 2, or 3"
;;
esac
[ -z "$var" ] && echo "var is empty"
[ -n "$var" ] && echo "var is not empty"
[ "$a" = "hello" ] && echo "Match"
[ "$a" != "world" ] && echo "Different"
[[ "apple" < "banana" ]] && echo "apple is less"
[[ "zebra" > "dog" ]] && echo "zebra is greater"
[[ $file == *.txt ]] && echo "Text file"
[ "$x" -eq 5 ] && echo "Equal"
(( x == 5 )) && echo "Equal"
[ "$x" -ne 3 ] && echo "Not Equal"
(( x != 3 )) && echo "Not Equal"
[ "$x" -lt 10 ] && echo "Less than 10"
[ "$x" -ge 0 ] && echo "Non-negative"
(( x < 10 )) && echo "Less than 10"
(( x >= 0 )) && echo "Non-negative"
[ -e "file.txt" ] && echo "File exists"
# Follow symlink
[ -f "file.txt" ] && echo "Regular file"
# -L preferred
[ -L "link.txt" ] && echo "It is a symbolic link"
[ -h "link.txt" ] && echo "It is a symbolic link"
[ -d "/tmp" ] && echo "Directory exists"
[[ -d "/tmp" ]] && echo "Directory exists"
[ -r "file.txt" ] && echo "Readable"
[[ -r "file.txt" ]] && echo "Readable"
[ -w "file.txt" ] && echo "Writable"
[[ -w "file.txt" ]] && echo "Writable"
[ -x "script.sh" ] && echo "Executable"
[[ -x "script.sh" ]] && echo "Executable"
[ -s "log.txt" ] && echo "Has content"
[[ $x -gt 0 && $x -lt 10 ]] && echo "Between 1 and 9"
[[ $user == "root" || $user == "admin" ]] && echo "Privileged user"
[[ ! -f "missing.txt" ]] && echo "File not found"
[ ... ]
is limited to only 1 condition, so we use &&
and ||
between conditions. Nested conditions not valid.
[ "$a" = "x" ] && [ "$b" = "y" ] && echo "Both match"
[ -f "$file" ] && [ -r "$file" ] && echo "File exists and is readable"
[ -z "$name" ] || [ ! -f "$file" ] && echo "Name empty or file not found"
[ -z "$input" ] || echo "Input is not empty"