Bash hello world
- Create a
.sh
file
emac task.sh
- Add some commands
#!/bin/bash
echo "Hello World"
- 给
task.sh
添加 executable 属性- By default, any newly created files are not executable regardless of its file extension suffix.
chmod +x task.sh
- 执行
./task.sh
Relative vs Absolute Path
- Root directroy
\
cd /
- Home directory
~
cd ~
- 上层目录
..
yaoxin@mrc-virt-0002:~/temp$ pwd
/home/yaoxin/temp
yaoxin@mrc-virt-0002:~/temp$ cd ..
yaoxin@mrc-virt-0002:~$ pwd
/home/yaoxin
// 向上返回两层目录
yaoxin@mrc-virt-0002:~/temp$ cd ../..
yaoxin@mrc-virt-0002:/home$ pwd
/home
- 当前目录
.
- 打印当前目录
pwd
Variables
#!/bin/bash
# This bash script is used to backup a user's home directory to /tmp/.
user=$(whoami)
input=/home/$user
output=/tmp/${user}_home_$(date +%Y-%m-%d_%H%M%S).tar.gz
tar -czf $output $input
echo "Backup of $input completed! Details about the output backup file:"
ls -l $output
- 首先 我们定义了 user, input, output 变量
$
sign:substituting variable names now prefixed by $ sign with their relevant values- $BASH_VERSION: 替换该关键字为环境变量中该关键字的定义
- Every line starting with # sign except shebang will not be interpreted by bash and will only serve as a programmer’s internal note.
- Parameter expansion
${parameter}
In our case, curly braces {} are required because our variable $user is followed by characters which are not part of its variable name
Input, Output and Error Redirections
- Redirect stdout to a file
>
- Redirect stderr
2>
- Redirect both stdout and stderr
&>
- Redirect Input
<
Functions
-
Functions are defined by using the function keyword and followed by function body enclosed by curly brackets.
-
The function definition must precede function call
#!/bin/bash
# This bash script is used to backup a user's home directory to /tmp/.
user=$(whoami)
input=/home/$user
output=/tmp/${user}_home_$(date +%Y-%m-%d_%H%M%S).tar.gz
# The function total_files reports a total number of files for a given directory.
function total_files {
find $1 -type f | wc -l
}
# The function total_directories reports a total number of directories
# for a given directory.
function total_directories {
find $1 -type d | wc -l
}
tar -czf $output $input 2> /dev/null
echo -n "Files to be included:"
total_files $input
echo -n "Directories to be included:"
total_directories $input
echo "Backup of $input completed!"
echo "Details about the output backup file:"
ls -l $output
- 在
function total_files
中 的$1
代表函数的第一个参数, 以此类推 - find: 在指定目录下查找文件
find path -option [ -print ] [ -exec -ok command ] {} \;
- wc: 计算文件的Byte数、字数、或是列数
wc [-clw][--help][--version][文件...]
-c或--bytes或--chars 只显示Bytes数。
-l或--lines 显示行数。
-w或--words 只显示字数。
--help 在线帮助。
--version 显示版本信息。
Numeric and String Comparisons
- If the return value is equal to 0, then the comparison evaluation is true. if the return value is equal to 1, the evaluation resulted as false.
- Using
echo $?
command to check evaluation result - Comparing strings with integers using numeric comparison operators will result in the error:
integer expression expected
#!/bin/bash
string_a="UNIX"
string_b="GNU"
echo "Are $string_a and $string_b strings equal?"
[ $string_a = $string_b ]
echo $?
num_a=100
num_b=100
echo "Is $num_a equal to $num_b ?"
[ $num_a -eq $num_b ]
echo $?
Output:
$ chmod +x compare.sh
$ ./compare.sh
Are UNIX and GNU strings equal?
1
Is 100 equal to 100 ?
0
Conditional Statements
#!/bin/bash
num_a=400
num_b=200
if [ $num_a -lt $num_b ]; then
echo "$num_a is less than $num_b!"
else
echo "$num_a is greater than $num_b!"
fi
fi
keyword closes our if conditional block
Positional Parameters
向即将执行的 script中传递参数( command line arguments )
~$ ./param.sh 1 2 3 4
1 2 4
4
1 2 3 4
# script named param
#!/bin/bash
echo $1 $2 $4
echo $#
echo $*
- Positional parameters are assigned via command line arguments and are accessible within a script as
$1, $2...$N
variables. - Using
$#
, we are printing the total number of supplied arguments - the
$*
, is used to print all arguments.
#!/bin/bash
# This bash script is used to backup a user's home directory to /tmp/.
if [ -z $1 ]; then
user=$(whoami)
else
if [ ! -d "/home/$1" ]; then
echo "Requested $1 user home directory doesn't exist."
exit 1
fi
user=$1
fi
input=/home/$user
output=/tmp/${user}_home_$(date +%Y-%m-%d_%H%M%S).tar.gz
function total_files {
find $1 -type f | wc -l
}
function total_directories {
find $1 -type d | wc -l
}
function total_archived_directories {
tar -tzf $1 | grep /$ | wc -l
}
function total_archived_files {
tar -tzf $1 | grep -v /$ | wc -l
}
tar -czf $output $input 2> /dev/null
src_files=$( total_files $input )
src_directories=$( total_directories $input )
arch_files=$( total_archived_files $output )
arch_directories=$( total_archived_directories $output )
echo "Files to be included: $src_files"
echo "Directories to be included: $src_directories"
echo "Files archived: $arch_files"
echo "Directories archived: $arch_directories"
if [ $src_files -eq $arch_files ]; then
echo "Backup of $input completed!"
echo "Details about the output backup file:"
ls -l $output
else
echo "Backup of $input failed!"
- See details
The above backup.sh script update introduces few new bash scripting techniques but rest for the code between Lines 5 - 13 should be by now self-explanatory. Line 5 is using a-z
bash option in combination with conditional if statement to check whether positional parameter $1 contains any value.-z
simply returns true if the length of the string which in our case is variable$1
is zero. If this is the case, we set$user
variable to a current user’s name.
Else on Line 8, we check if the requested user’s home directory exists by using -d bash option. Note the exclamation mark before the -d
option. Exclamation mark, in this case, acts as a negator. By default -d
option returns true if the directory exists, hence our ! just reverts the logic and on Line 9 we print an error message. Line 10 uses exit command causing script execution termination. We have also assigned exit value 1 as opposed to 0 meaning that the script exited with an error. If the directory check passes validation, on Line 12 we assign our$user
variable to positional parameter $1
as requested during by the user.
Bash Loops
For Loop
For loop is used to iterate through any given code for any number of supplied items in the list
The for loop consists of four Shell Reserved Words: for, in, do, done
.
Example1:
#!/bin/bash
for i in 1 2 3; do
echo $i
done
Example2:
While loop
#!/bin/bash
counter=0
while [ $counter -lt 3 ]; do
let counter+=1
echo $counter
done
Loop sumarry
#!/bin/bash
# This bash script is used to backup a user's home directory to /tmp/.
function backup {
if [ -z $1 ]; then
user=$(whoami)
else
if [ ! -d "/home/$1" ]; then
echo "Requested $1 user home directory doesn't exist."
exit 1
fi
user=$1
fi
input=/home/$user
output=/tmp/${user}_home_$(date +%Y-%m-%d_%H%M%S).tar.gz
function total_files {
find $1 -type f | wc -l
}
function total_directories {
find $1 -type d | wc -l
}
function total_archived_directories {
tar -tzf $1 | grep /$ | wc -l
}
function total_archived_files {
tar -tzf $1 | grep -v /$ | wc -l
}
tar -czf $output $input 2> /dev/null
src_files=$( total_files $input )
src_directories=$( total_directories $input )
arch_files=$( total_archived_files $output )
arch_directories=$( total_archived_directories $output )
echo "########## $user ##########"
echo "Files to be included: $src_files"
echo "Directories to be included: $src_directories"
echo "Files archived: $arch_files"
echo "Directories archived: $arch_directories"
if [ $src_files -eq $arch_files ]; then
echo "Backup of $input completed!"
echo "Details about the output backup file:"
ls -l $output
else
echo "Backup of $input failed!"
fi
}
for directory in $*; do
backup $directory
done;
- After reviewing the above script, you may have noticed that new function called backup. This function includes all of our previously written code.
For loop
at the end executes the newly defined backup function for each user directory supplied as an argument.$*
variable contains all arguments supplied on a command line upon the script execution.
Bash Arithmetics
Arithmetic Expansion
- enclose any mathematical expression inside double parentheses
expr command
Using the expr
command allows us to perform an arithmetic operation even without enclosing our mathematical expression within brackets or quotes. However, do not forget to escape asterisk multiplication sign to avoid expr: syntax error
let command
Similarly, as with expr command, we can perform bash arithmetic operations with let command. let command evaluates a mathematical expression and stores its result into a variable