Unit: 3.5
Link: https://lgwain.gitbooks.io/os/unit35.html
HomeWork: https://lgwain.gitbooks.io/os/lx3b.html
Shell脚本是什么?
通俗的解释就是一堆Linux命令的逻辑化处理。
为什么要编写Shell脚本?
在做开发的时候,有的时候需要部署环境或者是打包发布,往往都需要在终端里敲好多的命令才能做一件事,但是如果每次部署都要敲一堆命令,那么效率是非常低的,也会使人感到烦躁。所以,我们可以编写Shell脚本,将要执行的命令写在一起,用的时候只需要运行一下脚本就一切都搞定了。
从第一行开始!
为了确保Shell脚本可以正常运行,请将下面一行代码写在Shell脚本的第一行:
#!/bin/bash
确保了脚本总是运行在bash中。
如何执行Shell脚本?
首先我们先新建一个简单的Shell脚本,让它输出 Hello World!
。
$ touch t.sh
$ vi t.sh
# Coding...
$ cat t.sh
#!/bin/bash
echo Hello World!
(一)使用 bash ScriptName
执行Shell脚本:只需要对脚本有读的权限(chmod 444 ./t.sh
)
$ bash t.sh
Hello World!
(二)像运行命令一样 ./ScriptName
执行Shell脚本:需要对脚本有执行权限(chmod 555 ./t.sh
)
$ ./t.sh
Hello World!
(三)使用命令 source ScriptName
运行Shell脚本:同样要对脚本有执行权限
和前两种执行方式不同的是,前两种方式是在当前Shell中创建了一个子进程来执行相应的脚本,不会对父进程有影响,而命令 source
会在当前的Shell中执行相应的脚本,直接影响当前的进程。
$ source t.sh
Hello World!
只输出 Hello World!
看不出来效果,我们在脚本文件中加入一行切换目录的命令:
#!/bin/bash
cd ../
echo Hello World!
分别使用第二种和第三种方式执行,看效果:
$ pwd
/Users/yuchunyu97/Projects/www/Homework/os04/src/script
# 第二种
$ ./t.sh
Hello World!
$ pwd
/Users/yuchunyu97/Projects/www/Homework/os04/src/script
# 第三种
$ source t.sh
Hello World!
$ pwd
/Users/yuchunyu97/Projects/www/Homework/os04/src
pwd
命令可以显示当前所在的目录。
可以看出来第二种方式执行切换目录的命令并没有对当前的目录产生影响,而第三种方式使当前目录返回了上一级目录。
在终端输出 echo
、读取用户输入 read
# echo 命令介绍
$ cat t.sh
#!/bin/bash
# 输出字符串
echo "Hello World"
# 输出字符串也可以不加双引号
echo Hello World
# 输出双引号 "
echo \"Hello World\"
# echo命令默认换行,使用 -n 可以设置不换行
echo -n Please Input Something:
# 读取用户输入,并存入变量
read line
# 输出存在变量里的字符串
echo "Get It: $line"
# 使用单引号 ' 可以将变量输出成字符串
echo 'It is not a variable $line'
# 使用反引号 ` 执行命令
echo Current Time: `date`
# 使用大于号 > 将输出重定向到文件
echo This line is in a file > t.tmp
$ ./t.sh
Hello World
Hello World
"Hello World"
Please Input Something:Hi Shell Script
Get It: Hi Shell Script
It is not a variable $line
Current Time: 2017年11月 3日 星期五 15时33分52秒 CST
$ ls
t.sh t.tmp
$ cat t.tmp
This line is in a file
关于 echo
的详细介绍:Shell命令:echo 命令详解
# read 命令介绍
$ cat t.sh
#!/bin/bash
# -p 显示提示信息,并且不换行
# 可以同时接受多个值,以空格分隔
read -p "Enter your name and age separated by Space: " name age
echo "Hi, $name. Your age is $age"
# -t 限制用户的输入时间
read -t 5 -p "You have 5 Seconds to input: " line
echo -e "\nYour input is: $line"
# -s 可以不显示用户的输入
read -s -p "Enter Password: " passwd
echo -e "\nYour password is: $passwd"
$ ./t.sh
Enter your name and age separated by Space: Yuchunyu 20
Hi, Yuchunyu. Your age is 20
You have 5 Seconds to input:
Your input is:
Enter Password:
Your password is: MyPassword
测试/判断命令 test
在Linux中执行判断时,如果正确则返回
0
,如果错误则返回1
。
$?
临时存储当前判断的结果。
语法:
test expression or [ expression ] or [[ expression ]]
使用表达式来测试文件状态:
-f <file> 是否为文件
-d <file> 是否为目录
-r <file> 是否有读权限
-w <file> 是否有写权限
-x <file> 是否有执行权限
-s <file> 是否有非零大小
例:
$ chmod 444 t.tmp
$ ls -l t.tmp
-r--r--r-- 1 yuchunyu97 staff 23 11 3 15:39 t.tmp
$ cat t.sh
#!/bin/bash
test -f t.tmp
echo Is an ordinary file? $?
test -d t.tmp
echo Is a directory? $?
test -r t.tmp
echo Is Readable? $?
test -w t.tmp
echo Is Writable? $?
test -x t.tmp
echo Is Executable? $?
test -s t.tmp
echo Has Non-Zero Length? $?
$ ./t.sh
Is an ordinary file? 0
Is a directory? 1
Is Readable? 0
Is Writable? 1
Is Executable? 1
Has Non-Zero Length? 0
# 0 表示有
# 1 表示无
字符串测试:
-n <string> 字符串是否不为空
-z <string> 字符串是否为空
<string> == <string> 字符串是否相等
<string> != <string> 字符串是否不相等
例:
$ cat t.sh
#!/bin/bash
test -n ""
echo Empty String is not empty? $?
test -z ""
echo Empty String is empty? $?
test "str" == "str1"
echo \"str\" and \"str1\" are equal? $?
test "str" != "str1"
echo \"str\" and \"str1\" are not equal? $?
$ ./t.sh
Empty String is not empty? 1
Empty String is empty? 0
"str" and "str1" are equal? 1
"str" and "str1" are not equal? 0
算数测试:
<value> -eq <value> 是否相等
<value> -ne <value> 是否不相等
<value> -lt <value> 是否小于
<value> -le <value> 是否小于等于
<value> -gt <value> 是否大于
<value> -ge <value> 是否大于等于
例:
$ cat t.sh
#!/bin/bash
test 1 -eq 2
echo 1 equals 2? $?
test 1 -ne 2
echo 1 not equals 2? $?
test 7 -lt 7
echo 7 less than 7? $?
test 7 -le 7
echo 7 less than or equal 7? $?
test 7 -gt 6
echo 7 greater than 6? $?
test 7 -ge 6
echo 7 greater than or equal 6? $?
$ ./t.sh
1 equals 2? 1
1 not equals 2? 0
7 less than 7? 1
7 less than or equal 7? 0
7 greater than 6? 0
7 greater than or equal 6? 0
&& 和 ||
可以用于有条件的执行命令。
command1 && command2
如果command1成立,再执行command2
command1 || command2
如果command1不成立,再执行command2
例:
# 查看当前目录,有文件 t.tmp
$ ls
t.sh t.tmp
# 如果有 t.tmp,就删除
# 如果没有 e.file,就新建一个 e.file
$ cat t.sh
#!/bin/bash
(test -f t.tmp) && rm -f t.tmp
(test -f e.file) || touch e.file
# 执行脚本
$ ./t.sh
# 查看当前目录, t.tmp被删除了,新建了一个 e.file
$ ls
e.file t.sh
if
命令
语法:
if [ status(true) ]
then
process
elif [ status(true) ]
then
process
else
process
fi
注: if
和 elif
后面的空格不能省略,还有后面的 [ status ]
中,status两边的空格也不能省略。别忘了在最后加 fi
。
例:
$ cat t.sh
#!/bin/bash
read -p "Please input a number: " num
if [ $num -lt 10 ]
then
echo $num is less than 10
elif [ $num -gt 10 ]
then
echo $num is greater than 10
else
echo $num is equal to 10
fi
$ ./t.sh
Please input a number: 2
2 is less than 10
$ ./t.sh
Please input a number: 12
12 is greater than 10
$ ./t.sh
Please input a number: 10
10 is equal to 10
case
命令
语法:
case $var in
pattern1) command1 ;;
pattern2) command2 ;;
*) command3 ;;
esac
注:每一个 pattern
后面有两个分号 ;;
,最后要加 esac
。
例:
$ cat t.sh
#!/bin/bash
read -p "Please input \"yes\" or \"no\": " var
case $var in
[Yy][Ee][Ss])
echo Your input is YES;;
[Nn][Oo])
echo Your input is NO;;
*)
echo Input Error;;
esac
$ ./t.sh
Please input "yes" or "no": Yes
Your input is YES
$ ./t.sh
Please input "yes" or "no": no
Your input is NO
$ ./t.sh
Please input "yes" or "no": hello
Input Error
while
命令
语法:
while staues(true)
do
commands
[break]
[continue]
done
例:
$ cat t.sh
#!/bin/bash
guess=37
while true
do
read -p "Please input a number to guess: " num
if [ $num -eq $guess ]
then
echo Bingo! It\'s $num
break
elif [ $num -lt $guess ]
then
echo Please guess a bigger number.
continue
elif [ $num -gt $guess ]
then
echo Please guess a smaller number.
continue
fi
done
$ ./t.sh
Please input a number to guess: 30
Please guess a bigger number.
Please input a number to guess: 40
Please guess a smaller number.
Please input a number to guess: 35
Please guess a bigger number.
Please input a number to guess: 37
Bingo! It's 37
注:Shell脚本中给变量赋值时,等号 =
两边不能有空格。
for
命令
语法:
for identifier in list
do
commands to be executed on $identifier
done
例:
$ cat t.sh
#!/bin/bash
for i in {1..10}
do
echo $i
done
$ ./t.sh
1
2
3
4
5
6
7
8
9
10
$ cat t.sh
#!/bin/bash
for i in 1 2 3 0 6
do
echo $i
done
$ ./t.sh
1
2
3
0
6
$ cat t.sh
#!/bin/bash
for i in cat dog pig
do
echo $i
done
$ ./t.sh
cat
dog
pig
$ cat t.sh
#!/bin/bash
for i in `ls ../`
do
echo $i
done
$ ./t.sh
a.out
script
sh.c
Shell脚本的参数
在命令行上的参数传递给Shell脚本,被存在了特殊的变量里。
语法:
$1, $2, $3 ... 依次代表传给Shell脚本的参数
$@ 代表 "$1" "$2" "$3"
$* 代表 "$1 $2 $3"
$# 储存参数的个数
例:
$ cat t.sh
#!/bin/bash
echo First parameter: $1
echo Second parameter: $2
echo Number of parameters: $#
echo $@
echo $*
$ ./t.sh one two three four five
First parameter: one
Second parameter: two
Number of parameters: 5
one two three four five
one two three four five
shift
命令:位置参数可以用 shift
命令左移。比如 shift 3
表示原来的 $4
现在变成 $1
,原来的 $5
现在变成 $2
等等,原来的 $1
、 $2
、 $3
丢弃, $0
不移动。不带参数的 shift
命令相当于 shift 1
。
例:
$ cat t.sh
#!/bin/bash
while [ $# -gt 0 ]
do
echo 第一个参数为:$1
shift
done
$ ./t.sh 1 2 3 4 5
第一个参数为:1
第一个参数为:2
第一个参数为:3
第一个参数为:4
第一个参数为:5
这个命令可以让我们逐个的处理命令行参数。
算数相关的命令
可以使用 let
或者 $(( expr ))
来执行算数运算。
例:
$ cat t.sh
#!/bin/bash
let x=7+8
echo $x
echo $(( (6 + 8)*9 ))
$ ./t.sh
15
126
也可以使用命令 expr
。不过这个比前两个慢很多。注意使用 (
、 )
、*
的时候需要转义。
$ echo `expr 3 + 5`
8
$ expr 3 * ( 3 + 5 )
zsh: unknown file attribute:
# ( 、)、* 需要转义
$ expr 3 \* \( 3 + 5 \)
24
函数
语法:
function func_name() {
statements
[return]
}
例:
$ cat t.sh
#!/bin/bash
function show() {
echo "hello , $1"
}
show world
$ ./t.sh
hello , world