Shell脚本的基本使用
#!符号称为魔术数字,向内核告知需要在脚本解析行的程序。
是以#符号开始的行,后面的东西不会再被解析。
Bash shell程序一般由Linux命令和Bash shell命令、程序创建者、注释等组成。
执行许可的创建:chmod+x命令+文件名
一般局部变量使用小写字母,全局变量使用大写字母。
是内置命令,从终端或文件读取输入的字符串。
Read命令会读取一行,直到发现newline为止,行尾的newline读取为null。
[qwe@localhost aaa]$ ./question
您幸福吗?:是的
回答为是的
您怎么称呼?:wang Yue
您好? wang 先生
您住哪?:广州
原来住在广州啊!
您使用哪一种Linux发行版?:CentOs
原来使用的CentOs啊!
请输入具有代表性的三种linux发行版。:redHat CenOS QiLin
第三个位置写了QiLin
[qwe@localhost aaa]$ cat question
#!/bin/bash
#question.sh
echo -e "您幸福吗?:\c"
read answer
echo "回答为$answer"
echo -e "您怎么称呼?:\c"
read first list
echo "您好?$last $first 先生"
echo -n "您住哪?:"
read
echo 原来住在$REPLY啊!
read -p "您使用哪一种Linux发行版?:"
echo 原来使用的$REPLY啊!
echo -n "请输入具有代表性的三种linux发行版。:"
read -a dist
echo "第三个位置写了${dist[2]}"
Read 从标准输入读取一行,将结果值分配给REPLY内置变量
Read -a arrayname 读取命名为arrayname的数组目录 {目录名[第几个值]}
Read -p 等待输入,将内容保存在REPLY变量
Read -r 允许输入包含反斜杠(\)的内容
Read -e 用于交互式shell
使用declare命令可以将变量声明为整数型。
[qwe@localhost aaa]$ declare -i num
[qwe@localhost aaa]$ num=hello
[qwe@localhost aaa]$ echo $num
0
[qwe@localhost aaa]$ num=10+10
[qwe@localhost aaa]$ echo $num
20
[qwe@localhost aaa]$ num= 10 +10
bash: 10: command not found
只使用declare -i 命令可以声明为整数型的变量目录和值。
qwe@localhost aaa]$ declare -i
declare -ir BASHPID=""
declare -ir EUID="500"
declare -i HISTCMD=""
declare -i LINENO=""
declare -i MAILCHECK="60"
declare -i OPTIND="1"
declare -ir PPID="4628"
declare -i RANDOM=""
declare -ir UID="500"
declare -i num="20"
数分为10进制、2进制、8进制、16进制等,范围包括2~36进制。
[qwe@localhost aaa]$ declare -i x=016
[qwe@localhost aaa]$ echo $x
14
[qwe@localhost aaa]$ x=2#101
[qwe@localhost aaa]$ echo $x
5
[qwe@localhost aaa]$ x=8#13
[qwe@localhost aaa]$ echo $x
11
[qwe@localhost aaa]$ x=16#A2
[qwe@localhost aaa]$ echo $x
162
Let命令是bash内置命令,执行整数型算数运算并测试数字表达式。在命令执行help let就能查看帮助页面。
Bash只支持整数型运算,但是使用bc、awk实用工具即可执行更复杂的运算。
3.4 位置参数和命令行参数
3.4.1 位置参数
可以通过命令行将需要的信息传递给脚本。每个以脚本名后空格分隔的词将成为参数。
$0 $1...${10} 分别浏览位置参数
3.4.2 set命令和位置参数
$0 脚本名
$# 拥有位置参数个数值
$* 拥有位置参数的所有目录
$@ 等于$*
$*与$@上的区别:$*与$@上使用双引号就会包含其他含义。加双引号的$*变量参数目录成为1个字符串。加双引号的$@变量引用每个参数,每个词视为分隔的字符串。
3.5 条件语句和分支语句
3.5.1 test命令运算符
字符串
== 相等 != 不等
[string] 字符串是否为空 [-z string] 测试字符串长度是否为0
[-n string] 测试字符串长度是否非0 [-l string] 字符串长度
逻辑测试
-a 与 -o 或 ! 非
&& 与 || 或 ! 非
整数型运算
-eq 等于 -ne 不等于 -gt 大于 -ge 大于等于
-lt 小于 -le 小于等于
用于文件测试的二进制运算符
-nt 更晚使用 -ot 是否为上一个文件 -ef 是否有相同的设备和索引节点
3.5.2 if命令
If命令
Then
命令
命令
Fi
3.5.2.1 exit命令和“?”变量
使用exit命令终止脚本并返回命令行,脚本发生状况可以使用exit命令终止。
Exit命令的参数保存于shell的”?”变量。
3.5.2.2
检查null值
[qwe@localhost aaa]$ ./nullcheck
未输入第一个参数值.(null)
[qwe@localhost aaa]$ ./nullcheck 2
./nullcheck: line 4: [2: command not found
第一个参数值为2
[qwe@localhost aaa]$ ./nullcheck name
./nullcheck: line 4: [name: command not found
第一个参数值为name
[qwe@localhost aaa]$ cat nullcheck
#!/bin/bash
name=$1
if ["$name" == ""] # [! "$name"] 或 [-z "$name"]
then
echo "未输入第一个参数值.(null)"
else
echo 第一个参数值为$name
Fi
3.5.3 if/then/else命令
If 命令
Then
命令
Else
命令
Fi
3.5.4 文件测试
文件测试运算符:
-e filename 文件存在即为真
-d 文件存在且为目录即为真
-f 文件存在且是一般文件为真
-r/-w/-x 文件存在且可读、写、执行则为真
[qwe@localhost aaa]$ chmod +x filetest.sh
[qwe@localhost aaa]$ ./filetest.sh
使用方法: ./filetest.sh 文件名
[qwe@localhost aaa]$ ./filetest.sh name
name不是目录也不是文件
[qwe@localhost aaa]$ cat filetest.sh
#!/bin/bash
if [ -z $1 ]
then
echo 使用方法: ./filetest.sh 文件名
exit 1
fi
if [ -d $1 ]
then
echo "$1是目录"
elif [ -f $1 ]
then
if [ -r $1 -a -w $1 -a -x $1 ]
then
echo "$1文件是可读、写、执行的文件"
fi
else
echo "$1不是目录也不是文件"
fi
3.5.5 null命令
Null命令是内置命令,以冒号(:)标记,不执行任何命令并返回终止状态0。
[qwe@localhost aaa]$ chmod +x null2test.sh
[qwe@localhost aaa]$ ./null2test.sh
testfile中没有字符串
[qwe@localhost aaa]$ ./null2test.sh 洪吉童
testfile中没有洪吉童字符串
[qwe@localhost aaa]$ ./null2test.sh洪吉童
bash: ./null2test.sh洪吉童: No such file or directory
[qwe@localhost aaa]$ echo 洪吉童>filetest
[qwe@localhost aaa]$ echo 洪吉童> testfile
[qwe@localhost aaa]$ ./null2test.sh 洪吉童
[qwe@localhost aaa]$ echo $?
0
[qwe@localhost aaa]$ cat null2test.sh
#!/bin/bash
if grep "$1" testfile >& /dev/null
then
:
else
echo "testfile中没有$1字符串"
exit 1
Fi
3.5.6 case命令
Case命令结尾一般使用的是esac,即为case的缩写。
Case变量 in
Value1)
命令
;;
Value2)
命令
;;
*)
命令
;;
Esac
例子:
[qwe@localhost aaa]$ vi case_exam.sh
[qwe@localhost aaa]$ chmod +x case_exam.sh
[qwe@localhost aaa]$ ./case_exam.sh
请选择启动或终止程序
1.启动web服务器
2.终止web服务器
3.重启web服务器
1
Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using localhost.localdomain for ServerName
(13)Permission denied: make_sock: could not bind to address [::]:80
no listening sockets available, shutting down
Unable to open logs
[FAILED]
web服务器已开始
[qwe@localhost aaa]$ 2
bash: 2: command not found
[qwe@localhost aaa]$ ./case_exam.sh
请选择启动或终止程序
1.启动web服务器
2.终止web服务器
3.重启web服务器
2
rm: cannot remove `/var/run/httpd/httpd.pid': Permission deniedLED]
rm: cannot remove `/var/run/httpd/httpd.pid': Permission denied
web服务器已终止
[qwe@localhost aaa]$ ./case_exam.sh
请选择启动或终止程序
1.启动web服务器
2.终止web服务器
3.重启web服务器
3
rm: cannot remove `/var/run/httpd/httpd.pid': Permission deniedLED]
rm: cannot remove `/var/run/httpd/httpd.pid': Permission denied
Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using localhost.localdomain for ServerName
(13)Permission denied: make_sock: could not bind to address [::]:80
no listening sockets available, shutting down
Unable to open logs
[FAILED]
web服务器已重启
[qwe@localhost aaa]$ cat case_exam.sh
#!/bin/bash
echo "请选择启动或终止程序"
cat <<- ENDIT
1.启动web服务器
2.终止web服务器
3.重启web服务器
ENDIT
read choice
case "$choice" in
1) STATUS="开始"
/etc/init.d/httpd start
;;
2) STATUS="终止"
/etc/init.d/httpd stop
;;
3) STATUS="重启"
/etc/init.d/httpd restart
;;
esac
echo "web服务器已$STATUS"
Cat <<-ENDIT命令就是here文档,该文档使用ENDIT字符串标记cat命令的结束。
3.6 循环
3.6.1 while循环
[qwe@localhost aaa]$ vi say.sh
[qwe@localhost aaa]$ ./say.sh
输入q就能终止
需要终止请输入q:w
需要终止请输入q:1
需要终止请输入q:0
需要终止请输入q:Q
已输入q,开始终止!
[qwe@localhost aaa]$ cat say.sh
#!/bin/bash
echo 输入q就能终止
go=start
while [[ -n "$go" ]]
do
echo -n 需要终止请输入q:
read word
if [[ $word == [Qq] ]] #[ "word" = q -o "word" = Q]
then
echo "已输入q,开始终止!"
go=
fi
done
说明:使用-n选项判断go变量是否为null,-n选项是test命令。
3.6.2 until循环语句
Until循环语句命令虽然类似于while命令,但只有在until后面的命令执行失败时(终止状态值非0)才执行循环语句。遇到done关键字就返回循环语句顶端,until命令重新检测命令的终止状态。重复循环语句直到命令终止的状态为0。
例子演示:
[qwe@localhost aaa]$ chmod +x hour.sh
[qwe@localhost aaa]$ ./hour.sh
0上午
1上午
2上午
3上午
4上午
5上午
6上午
7上午
8上午
9上午
10上午
11上午
12中午
13下午
14下午
15下午
16下午
17下午
18下午
19下午
20下午
21下午
22下午
23下午
[qwe@localhost aaa]$ vi hour.sh
[qwe@localhost aaa]$ cat hour.sh
#!/bin/bash
hour=0
until (( hour >= 24 ))
do
case "$hour" in
[0-9]|1[0-1])
echo $hour上午
;;
12) echo $hour中午
;;
*) echo $hour下午
;;
esac
((hour+=1))
Done
3.6.3 select命令和菜单
Case命令和select命令一起使用,用户可以从菜单选择、命令执行中选择select命令。
使用lines和columns变量可以决定显示到终端的菜单项目页面。
Select命令是循环语句命令,故使用break命令退出循环语句,使用exit命令终止脚本。
Select 变量名 in 词目录
Do
命令
done
PS3提示符用于输入,默认设置的SP3为#?。显示PS3提示符之后,shell就等待用户输入。
3.7 循环管理语句命令
3.7.1 shift命令
Shift命令按照指定数字向左移动参数目录。无参数的shift命令可将参数目录向左移动1次。也就是说,删除最左侧的参数。
[qwe@localhost aaa]$ ./shift.sh
苹果 桃子
May 23 02:12:24 PDT 2020
02:12:24 PDT 2020
[qwe@localhost aaa]$ cat shift.sh
#!/bin/bash
set 梨 葡萄 苹果 桃子
shift 2
echo $*
set $(date)
shift
echo $*
shift 2
echo $*
说明:上面的例子是使用set设置环境变量,然后执行shift进行删除最左边的对象。
3.7.2 break命令和continue命令
使用内置的break命令可以立即强制终止循环语句,但并不是终止整个程序。
使用continue命令时,若状态值为true就会忽略continue后面的左右命令,返回循环语句顶端。在重叠循环的最内侧循环语句创建continue命令,就返回最内侧循环语句的顶端;如果同时使用循环语句和数字参数,就返回需要循环语句顶端。
3.7.3 重叠循环语句和循环语句管理
使用重叠循环语句的时候,可以向break和continue命令赋予数字,所以可以从内侧循环语句向外侧移动。
Continue n:移动到第n个循环语句的开始
N:最内侧循环语句为1
下一个外侧循环语句为2
下一个外侧循环语句为3...
3.8 I/O重定向和子shell
3.8.1 用管道连接循环语句结果和指令
[qwe@localhost aaa]$ ./loop_com.sh
1
3
5
9
[qwe@localhost aaa]$ cat loop_com.sh
#!/bin/bash
for i in 1 5 3 9
do
echo $i
done | sort -n
3.8.2 在后台使用循环语句
可以在后台自行循环语句。执行循环语句以终止进程期间,无需等待,可以执行其他操作。
[qwe@localhost aaa]$ cat xunhuan.sh
#!/bin/bash
for person in root muti marry linux
do
mail $person < mail.txt
done &
说明:同之前的脚本文件一样,在循环语句结束的done关键字后面使用&符号,就可以在后台执行for循环语句。
3.8.3 IFS和循环语句
Shell内部字段分隔符(IFS)评估空格、Tab、newline字符,并可成为read、set、for等词目录解析命令的词分隔符。
3.9 函数
3.9.1 解除函数设置
使用unset命令删除保存于内存的函数。
Unset -f 函数名
3.9.2 导出函数
向子shell导出函数后即可在子shell中使用函数。
Exprot -f 函数名
3.9.3 函数参数和返回值
1. 参数:使用位置参数可以将参数传递给函数。
2.内置local函数:局部变量只能用于函数内部,使用local函数定义局部变量。终止函数就能删除局部变量。
3.内置return函数:可以在终止函数而调用的函数位置上使用return命令返回程序管理。
3.10 调试Bash脚本
Bash命令使用-n选项时,可不执行命令而检查语法脚本。
Bash -x 脚本名 替换变量后执行前,显示脚本各行
Bash -v 脚本名 执行前显示脚本各行
Bash -n 脚本名 解析但不执行
Set -x 在脚本跟踪执行
Set +x 在脚本不跟踪执行