Intro
There are different kinds of shells:
- Bourne Shell(
/usr/bin/sh
or/bin/sh
) - Bourne Again Shell(
/bin/bash
) - C Shell(
/usr/bin/csh
) - K Shell(
/usr/bin/ksh
) - Shell for Root(
/sbin/sh
) - …
But in this blog, we will basically focus on bash
.
Basics
Hello World!
#!/bin/bash
echo "Hello World!"
Permission
chmod +x ./test.sh # gives permission to this bash script
Run
# the following command need permission
./test.sh
# the following two methods doesn't need permission
sh test.sh # this method lead to the usage of dash instead of bash
# so problems might happen
bash test.sh
Variables
Fundamentals
1 #!/bin/bash
2 echo "======================================================="
3 echo ">> Preparing to print out the files at /home/yzy/Downloads"
4 for file in `ls /home/yzy/Downloads`; do
5 echo "There are files called ${file} at /home/yzy/Downloads/"
6 done
7 echo "======================================================="
8 echo ">> Preparing to pring out my skills"
9 for skill in Ada Coffe Action Java; do
10 echo "I am good at ${skill}Script"
11 done
12 echo "======================================================="
13 echo ">> Reset variables"
14 your_name="tom"
15 echo $your_name
16 your_name="Juillet"
17 echo $your_name
18 echo "======================================================="
19 echo ">> Play with read-only variable"
20 myUrl="https://www.zhiyuanyao.com"
21 readonly myUrl
22 # You are not able to change the variable here
23 # myUrl="http://www.w3cschool.cc"
24 echo "======================================================="
25 echo ">> Playing with unset"
26 myVar="Hello!"
27 unset myVar
28 echo $myVar
29 # You will not see anything here
String
1 #!/bin/bash
2 echo "======================================================="
3 echo ">> Greeting"
4 your_name='ZhiyuanYaoJ'
5 greeting="Hello, I know your are \"$your_name\"!"
6 greeting_1="Hello, "$your_name"!"
7 greeting_2="Hello, ${your_name}!"
8 echo ${greeting} ${greeting_1} ${greeting_2}
9 printf "${greeting}\n${greeting_1}\n${greeting_2}\n"
10 echo "======================================================="
11 echo ">> Length of string"
12 echo "Length of your_name = ${#your_name}"
13 echo "======================================================="
14 echo ">> Substring"
15 var="http://www.aaa.com/123.htm"
16 echo "原始 String:"
17 echo " var = \""${var}"\""
18 printf "从左边开始删除第一个'//'及左边的所有字符:\n var#*// = \""${var#*//}"\"\n"
19 printf "从右边开始删除第一个'/'及左边的所有字符:\n var##*/ = \""${var##*/}"\"\n"
20 echo "从右边开始删除第一个'/'及右边的所有字符:"
21 echo " var%/* = \""${var%/*}"\""
22 printf "从右边开始删除最后一个'/'及右边的字符:\n var%%/* = \""${var%%/*}"\"\n"
23 printf "从左边第 1 个字符开始截取 5 个字符:\n var:0:5 = \""${var:0:5}"\"\n"
24 printf "查找子字符串 \'1\' 或 \'m\' 的位置(优先输出靠左的字符位置):\n "`expr index "${var}" 1m`"\n"
25 echo "======================================================="
Outcome:
=======================================================
>> Greeting
Hello, I know your are "ZhiyuanYaoJ"! Hello, ZhiyuanYaoJ! Hello, ZhiyuanYaoJ!
Hello, I know your are "ZhiyuanYaoJ"!
Hello, ZhiyuanYaoJ!
Hello, ZhiyuanYaoJ!
=======================================================
>> Length of string
Length of your_name = 11
=======================================================
>> Substring
原始 String:
var = "http://www.aaa.com/123.htm"
从左边开始删除第一个'//'及左边的所有字符:
var#*// = "www.aaa.com/123.htm"
从右边开始删除第一个'/'及左边的所有字符:
var##*/ = "123.htm"
从右边开始删除第一个'/'及右边的所有字符:
var%/* = "http://www.aaa.com"
从右边开始删除最后一个'/'及右边的字符:
var%/* = "http:"
从左边第 1 个字符开始截取 5 个字符:
var:0:5 = "http:"
查找子字符串 '1' 或 'm' 的位置(优先输出靠左的字符位置):
18
=======================================================
Array
Operations
1 #!/bin/bash
2
3 arr=(
4 1
5 1
6 2
7 3
8 5
9 8
10 13
11 )
12
13 # get all elements
14 echo "Initialized arr: "${arr[*]}
15
16 # define specific element
17 echo "Mess a bit with arr..."
18 echo "set: arr[0]=13"
19 echo "set: arr[20]=20"
20 arr[0]=13
21 arr[20]=20
22
23 # get an element
24 tmp=${arr[19]}
25
26 echo "arr[19] = "${tmp}
27 echo "arr[20] = "${arr[20]}
28 echo "All elements: "${arr[*]}
29
30 echo "len(arr) = "${#arr[*]}
31 echo "len(arr[1]) = "${#arr[1]}
32 echo "len(arr[20]) = "${#arr[20]}
Outcome:
# bash ./array.sh
Initialized arr: 1 1 2 3 5 8 13
Mess a bit with arr...
set: arr[0]=13
set: arr[20]=20
arr[19] =
arr[20] = 20
All elements: 13 1 2 3 5 8 13 20
len(arr) = 8
len(arr[1]) = 1
len(arr[20]) = 2
Together with Loop
A=1
my_arry=($A B C D)
echo "第一个元素为: ${my_arry[0]}"
echo "第二个元素为: ${my_arry[1]}"
echo "第三个元素为: ${my_arry[2]}"
echo "第四个元素为: ${my_arry[3]}"
echo "-------FOR循环遍历输出数组--------"
for i in ${my_arry[@]};
do
echo $i
done
echo "-------::::WHILE循环输出 使用 let i++ 自增:::::---------"
j=0
while [ $j -lt ${#my_arry[@]} ]
do
echo ${my_arry[$j]}
let j++
done
echo "--------:::WHILE循环输出 使用 let "n++ "自增: 多了双引号,其实不用也可以:::---------"
n=0
while [ $n -lt ${#my_arry[@]} ]
do
echo ${my_arry[$n]}
let "n++"
done
echo "---------::::WHILE循环输出 使用 let m+=1 自增,这种写法其他编程中也常用::::----------"
m=0
while [ $m -lt ${#my_arry[@]} ]
do
echo ${my_arry[$m]}
let m+=1
done
echo "-------::WHILE循环输出 使用 a=$[$a+1] 自增,个人觉得这种写法比较麻烦::::----------"
a=0
while [ $a -lt ${#my_arry[@]} ]
do
echo ${my_arry[$a]}
a=$[$a+1]
done
Outcome:
# bash array_loop.sh
第一个元素为: 1
第二个元素为: B
第三个元素为: C
第四个元素为: D
-------FOR循环遍历输出数组--------
1
B
C
D
abc
-------::::WHILE循环输出 使用 let i++ 自增:::::---------
1
B
C
D
abc
--------:::WHILE循环输出 使用 let n++ 自增: 多了双引号,其实不用也可以:::---------
1
B
C
D
abc
---------::::WHILE循环输出 使用 let m+=1 自增,这种写法其他编程中也常用::::----------
1
B
C
D
abc
-------::WHILE循环输出 使用 a=1 自增,个人觉得这种写法比较麻烦::::----------
1
B
C
D
abc
Arguments
1 #!/bin/bash
2
3 echo "Shell 传递参数实例!";
4 echo "执行的文件名:$0";
5 echo "第一个参数为:$1";
6 echo "第二个参数为:$2";
7 echo "第三个参数为:$3";
8
9 if [ -n "$1" ]; then
10 echo "包含第一个参数"
11 else
12 echo "没有包含第一参数"
13 fi
14
15 echo "参数个数为:$#";
16 echo "传递的参数作为一个字符串显示:$*";
17
18 echo "-- \$* 演示 ---"
19 for i in "$*"; do
20 echo $i
21 done
22
23 echo "-- \$@ 演示 ---"
24 for i in "$@"; do
25 echo $i
26 done
27
28 echo "-- \$\$ 演示 ---"
29 echo "脚本运行的当前进程 ID 号"
30 echo $$
31
32 echo "-- \$! 演示 ---"
33 echo "后台运行的最后一个进程的 ID 号"
34 echo $!
35
36 echo "-- \$- 演示 --"
37 echo "显示Shell使用的当前选项,与set命令功能相同"
38 echo $-
39
40 echo "-- \$? 演示 --"
41 echo "显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误"
42 echo $?
Outcome:
# bash ./arg.sh 1 2
Shell 传递参数实例!
执行的文件名:./arg.sh
第一个参数为:1
第二个参数为:2
第三个参数为:
包含第一个参数
参数个数为:2
传递的参数作为一个字符串显示:1 2
-- $* 演示 ---
1 2
-- $@ 演示 ---
1
2
-- $$ 演示 ---
脚本运行的当前进程 ID 号
11959
-- $! 演示 ---
后台运行的最后一个进程的 ID 号
-- $- 演示 --
显示Shell使用的当前选项,与set命令功能相同
hB
-- $? 演示 --
显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误
0
Operator
Arithmetic Operator
#!/bin/bash
a=10
b=20
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a - $b`
echo "a - b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
val=`expr $b / $a`
echo "b / a : $val"
val=`expr $b % $a`
echo "b % a : $val"
if [ $a == $b ]
then
echo "a 等于 b"
fi
if [ $a != $b ]
then
echo "a 不等于 b"
fi
Relational Operator
#!/bin/bash
a=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a 等于 b"
else
echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
echo "$a -ne $b: a 不等于 b"
else
echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
echo "$a -gt $b: a 大于 b"
else
echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
echo "$a -lt $b: a 小于 b"
else
echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
echo "$a -ge $b: a 大于或等于 b"
else
echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
echo "$a -le $b: a 小于或等于 b"
else
echo "$a -le $b: a 大于 b"
fi
Outcome:
10 -eq 20: a 不等于 b
10 -ne 20: a 不等于 b
10 -gt 20: a 不大于 b
10 -lt 20: a 小于 b
10 -ge 20: a 小于 b
10 -le 20: a 小于或等于 b
Boolean Operator
#!/bin/bash
a=10
b=20
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi
Outcome:
10 != 20 : a 不等于 b
10 小于 100 且 20 大于 15 : 返回 true
10 小于 100 或 20 大于 100 : 返回 true
10 小于 5 或 20 大于 100 : 返回 false
Logical Operator
#!/bin/bash
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
if [[ $a -lt 100 || $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
Outcome:
返回 false
返回 true
String Operator
#!/bin/bash
a="abc"
b="efg"
if [ $a = $b ]
then
echo "$a = $b : a 等于 b"
else
echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
echo "-z $a : 字符串长度为 0"
else
echo "-z $a : 字符串长度不为 0"
fi
if [ -n $a ]
then
echo "-n $a : 字符串长度不为 0"
else
echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
echo "$a : 字符串不为空"
else
echo "$a : 字符串为空"
fi
Outcome:
abc = efg : a 不等于 b
abc != efg : a 不等于 b
-z abc : 字符串长度不为 0
-n efg : 字符串长度不为 0
abc : 字符串不为空
File Test Operator
#!/bin/bash
file=${PWD}"/test.sh"
echo "file=${file}"
if [ -r $file ]
then
echo "文件可读"
else
echo "文件不可读"
fi
if [ -w $file ]
then
echo "文件可写"
else
echo "文件不可写"
fi
if [ -x $file ]
then
echo "文件可执行"
else
echo "文件不可执行"
fi
if [ -f $file ]
then
echo "文件为普通文件"
else
echo "文件为特殊文件"
fi
if [ -d $file ]
then
echo "文件是个目录"
else
echo "文件不是个目录"
fi
if [ -s $file ]
then
echo "文件不为空"
else
echo "文件为空"
fi
if [ -e $file ]
then
echo "文件存在"
else
echo "文件不存在"
fi
Outcome:
file=/home/yzy/Projects/shell/test.sh
文件可读
文件可写
文件可执行
文件为普通文件
文件非目录
文件不为空
文件存在
Function
1 #!/bin/bash
2
3 echo "======================================================="
4 demoFun(){
5 echo "这是我的第一个 shell 函数!"
6 }
7 echo "-----函数开始执行-----"
8 demoFun
9 echo "-----函数执行完毕-----"
10 echo "======================================================="
11 funWithReturn(){
12 echo "这个函数会对输入的两个数字进行相加运算..."
13 echo "输入第一个数字: "
14 read aNum
15 echo "输入第二个数字: "
16 read anotherNum
17 echo "两个数字分别为 $aNum 和 $anotherNum !"
18 return $(($aNum+$anotherNum))
19 }
20 funWithReturn
21 echo "输入的两个数字之和为 $? !"
Outcome:
=======================================================
-----函数开始执行-----
这是我的第一个 shell 函数!
-----函数执行完毕-----
=======================================================
这个函数会对输入的两个数字进行相加运算...
输入第一个数字:
1
输入第二个数字:
2
两个数字分别为 1 和 2 !
输入的两个数字之和为 3 !
Useful Function:
function mcd() { [ -n "$1" ] && mkdir -p "$@" && cd "$1"; }