编写shell脚本(shell脚本编程)
编写shell脚本(shell脚本编程)使用shell命令编写的文件可执行,我们称之为脚本。脚本一般是一个可执行文件。Shell 存在于系统之上用户之下,介于用户系统之间,用来负责于用户和系统直接对话。4)、熟悉常见的 Linux 网络服务的部署、优化、日志分析及排错学习Shell 脚本的目的在于对公工作中系统及服务等进行自动化的管理,因此如果不熟悉工作中的网络服务,就会很难使用shell 编程处理这些服务;不掌握网络服务等知识,就会让Shell开发者的能力打折扣,甚至只是掌握了 shell 编程的基本语法,并不能真正的学好shell编程。Shell 是一个命令解释器,它的作用是解释执行用户输入的命令及程序等,用户没输入一条命令,Shell 解释器就会执行一天命令,从键盘输入的命令,就会立即得到执行结果的对话方式,我们称之为 交互式shell。
为什么学习shell编程Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。每一位合格的Linux 系统管理员或运维工程师,都需要能够熟练地编写 Shell脚本,并能够阅读Linux系统自带的系统脚本内容,只有这样才能提升运维人员的工作效率,适合日益复杂的工作环境,减少不必要的重复性工作,从而为个人的职场发展尊定较好的基础。
学习 shell 编程需要掌握的基础1)、熟练使用 vim 文本编辑工具,熟悉SSH 及 .vimrc 配置等
2)、要掌握基础Linux 命令,文本的 增删改查、环境变量的配置使用。
3)、掌握Linux正则表达式及三剑客: grep sed awk的基本使用
4)、熟悉常见的 Linux 网络服务的部署、优化、日志分析及排错
学习Shell 脚本的目的在于对公工作中系统及服务等进行自动化的管理,因此如果不熟悉工作中的网络服务,就会很难使用shell 编程处理这些服务;不掌握网络服务等知识,就会让Shell开发者的能力打折扣,甚至只是掌握了 shell 编程的基本语法,并不能真正的学好shell编程。
什么是 ShellShell 是一个命令解释器,它的作用是解释执行用户输入的命令及程序等,用户没输入一条命令,Shell 解释器就会执行一天命令,从键盘输入的命令,就会立即得到执行结果的对话方式,我们称之为 交互式shell。
Shell 存在于系统之上用户之下,介于用户系统之间,用来负责于用户和系统直接对话。
什么是 Shell 脚本使用shell命令编写的文件可执行,我们称之为脚本。脚本一般是一个可执行文件。
脚本语言的种类- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for root(/sbin/sh
注意:查看当前系统支持的shell类型
[root@localhost ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
其他类型的语言
Php:网页程序语言,动态脚本语言。
Perl:perl脚本语言功能比shell脚本语言强大的多,2010年以前非常流行,目前已在淘汰的边缘。
python:Python脚本语言近几年非常火的语言,人工智能,web 开发,数据分析,运维脚本开发等都非常好用,入门门槛低
Shell 脚本语言的有点Shell 脚本语言的优势在于处理偏操作系统底层的业务,如Linux系统内部的很多应用都是使用shell脚本语言开发的,对于一下常规业务操作,使用shell更符合Linux运维 简单、易用、高效的三大原则。
操作系统默认shellCentos RedHat rockylinux 默认使用shell都是Bourne Again shell(bash)
通过以下两种方法查看系统默认shell类型:
[root@ym ~]# echo $SHELL
/bin/bash
[root@ym ~]# grep ^root /etc/passwd
root:x:0:0:root:/root:/bin/bash
Shell 脚本的创建与执行
- 打开一个系统脚本文件,我们可以查看脚本的格式
- 脚本的命名:脚本的拓展名.sh结尾
- 系统加载shell初始化文件:
/etc/profile # 系统初始化shell环境配置文件
/etc/profile.d/ # 目录存放系统初始化加载的sh脚本文件
~/.bash_profile # 环境变量设置文件
~/.bashrc # 当前登录用户的环境变量配置文件(可能不存在)
- Shell脚本执行:
shell脚本的执行过程
通常情况下,在执行shell脚本是,会向系统内核请求启动一个新的进程,在该进程中执行脚本命令及子进程脚本
shell 脚本通常采用一下集中方式执行 实例: bash test.sh 或 sh test.sh ./test.sh 这种方式需要test.sh有可执行权限 source test.sh 或 . test.sh 这种方式一般是读入脚本内容
- shell脚本的第一行是指定脚本解释器,通常为: #!/bin/bash 或 #!/bin/sh
- 代码规范实例:
1、#! /bin/bash
# : 代表注释 #!代表特例 /bin/bash 命令解释器的绝对路径
2、 需要描述脚本的功能、作者、时间、用法、版本的信息
# Name:脚本的名字
# Desc:功能描述 Describe
# Path:存放路径
# Usage:脚本的使用方法
# Update:更新时间
# Author: 作者
# Relase: 版本
什么是Shell变量1)、什么是变量
简单来说变量就是用一个固定的字符串代替更多的的内容,变量是一个可变化的量一个不固定的量
2)、变量的命名规则变量名的命名须遵循如下规则:
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
运行shell时,会同时存在三种变量:
- 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
- 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
- shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
- 局部变量只针对于当前shell 生效
- 全局变量只针对于整个操作系统生效
- set 输出所有变量,包括全局变量、局部变量
- env 只显示全局变量
- declare 输出所有变量,如同 set
- export 只显示和设置环境变量
- 系统中已经存在一些环境变量如:HOME PATH SHELL UID USER MAIL 等,在用户登录之前就已经备/bin/longin 程序设置好。
首先按照变量的命名规则使用指定字符,写在等号的左边作为变量的名称(标记),在写一个字符作为值赋值给变量名。
[root@ym ~]# ym_123=hello # 定义一个变量名称叫 ym_123
[root@ym ~]# echo $ym_123 # 使用echo 输出变量所对应的值
hello
- 单引号:调用变量事不管里面有什么都要原样输出,但引号的内容;
- 双引号:调用变量时可以调用变量所赋的值,显示变量的内容呢;
- 反引号:可以调用命令并把命令所输出的结果复制给变量;
- 无引号:可以复制一个连续的字母或数字给变量,中间不能有空格;
- export variname=value
- declare [-aixr] variable 参数: -a :将后面名为 variable 的变量定义成为数组 (array) 类型 -i :将后面名为 variable 的变量定义成为整数数字 (integer) 类型 -x :用法与 export 一样 就是将后面的 variable 变成环境变量; -r :将变量设定成为 readonly 类型 该变量不可被更改内容 也不能 unset
- 用户环境变量配置 .bashrc .bash_profile
- 全局环境变量配置 /etc/profile /etc/bashrc /etc/profile.d/
[root@ym ~]# echo $PATH # 查看当前系统的环境变量
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@ym ~]# export PATH=$PATH:/usr/local/bin # 添加路径到系统的环境变量中(临时设置系统环境变量,重启操作系统丢失,需要写在配置文件中)
Shell 中特殊的变量
变量 |
描述 |
$0 |
当前脚本的文件名 |
$n |
传递给脚本或函数的参数 |
$# |
传递给脚本或函数的参数个数 |
$* |
传递给脚本或函数的所有参数 |
$@ |
传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会讲到。 |
$? |
上个命令的退出状态,或函数的返回值 |
$$ |
当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID |
set -- " I an hostname"
echo $# # 参数个数
#测试 $* $@ 不带引号
[root@localhost ~]# echo $2
handsone
[root@localhost ~]# echo $*
i am handsone tdlinux
[root@localhost ~]# echo $@
i am handsone tdlinux
[root@localhost ~]# for i in $*;do echo $i;done
i
am
handsone
tdlinux
[root@localhost ~]# for i in $@;do echo $i;done
i
am
handsone
tdlinux
#测试 $* $@ 带双引号
[root@localhost ~]# for i in "$*";do echo $i;done
i am handsone tdlinux
#"$@":把变量分割成:$1 $2 $3
[root@localhost ~]# for i in "$@";do echo $i;done
i am
handsone
tdlinux
实例:$_ 和 himBH
$- 记录的是当前配置打开的shell选项, 而 himBH 是默认值
himBH 每个字母代表着一个shell选项,具体如下:
h - hashall # bash 的 hash 功能,可以实现让某些 command 和 具体路径 绑定在一起。
i - interactive-comments # 配置在交互 shell 模式下,是否允许注释。
m - monitor # 配置是否打开控制 Job control 功能。
B - braceexpand # 关于括号使用的flag,打开后可以快捷地实现某些效果
H- history #是否允許用 “感叹号 ! history number ” 来执行历史命令
可以通过 set -o 查看来确认打开状态
- hash 哈希命令参数:
-l 显示哈希表示所有的项目
-r 清除哈希表所有项
-d <名称> 删除哈希表其中的一项
-p <路径> 向哈希表中增加一项内容,添加后就可以使用了
-t <命令> 显示hash表中命令的完整路径,如果没有就会报not found错误
实例:hash
[root@ym ~]# bash # 进入一个全新的 shell
[root@ym ~]# hash
hash: hash table empty # 由于是新建 shell,所以hash表为空,符合预期
[root@ym ~]# ls -l
[root@ym ~]# hash
hits command
1 /usr/bin/ls
[root@ym ~]# top
[root@ym ~]# hash
hits command
1 /usr/bin/ls
1 /usr/bin/top
[root@ym ~]# uptime
17:56:40 up 1138 days 7 min 1 user load average: 0.47 0.36 0.28
[root@ym ~]# hash # 可以看到hash表在不断更新
hits command
1 /usr/bin/uptime
1 /usr/bin/ls
1 /usr/bin/top
[root@ym ~]# hash -l
builtin hash -p /usr/bin/uptime uptime
builtin hash -p /usr/bin/ls ls
builtin hash -p /usr/bin/top top
[root@ym ~]# hash -p /tmp/mydate date # 手动添加hash表
[root@ym ~]# hash -l
builtin hash -p /usr/bin/uptime uptime
builtin hash -p /tmp/mydate date # 添加成功
builtin hash -p /usr/bin/ls ls
builtin hash -p /usr/bin/top top
[root@ym ~]# date
bash: /tmp/mydate: No such file or directory # 由于手动添加的hash表指向执行文件不存在,所以报错,这说明新增的hash表确实在work
[root@ym ~]# hash -d date # 手动清楚刚加的hash表,使用 -r 则全部清除
[root@ym ~]# hash -l
builtin hash -p /usr/bin/uptime uptime
builtin hash -p /usr/bin/ls ls
builtin hash -p /usr/bin/top top
[root@ym ~]# date # 恢复
Sun Jan 19 18:02:45 CST 2022
- i 可以在交互shell 中使用 # 号注释
- m 任务控制:
Ctrl z 后台运行
fg 命令将后台任务恢复到前台
- B 可以使用 {} 来执行命令
- history 历史命令:
!! : 返回并执行最近的一个历史命令 !n : 返回并执行第 n 个历史命令
8)、bash shell 内置变量命令bash shell 包含一些内置命令。常用的内部命令有:echo、eval、exec、export、read、shift。下面介绍一些具体的用法
8.1)、echo args 可以使用字符和变量的组合
echo 常用的参数列表
参数 |
说明 |
-n |
不换行输出 |
-e |
解释转移字符 |
\n |
换行输出 |
\r |
回车 |
\t |
制表符 |
\b |
退格删除前一个字符 |
\v |
纵向制表符 |
-E |
不解析转义字符 |
\a |
发出警告的凤鸣声 |
8.2)、eval args:当shell 程序执行到eval语句时,shell 读入参数args,并将它们组合成新的可执行命令
[root@ym test]# cat test.sh
#!/bin/sh
echo $0
echo \$$#
eval "echo \$$#"
[root@ym test]# sh test.sh a b c
test.sh
$3
c
8.3)、exec cmd : exec 命令能够在不创建子shell进程的前提下,在当前shell中执行命令。
#!/bin/sh
seq 1 5 > /tmp/test.log
exec < /tmp/test.log
cat /tmp/test.log
while read line
do
echo $line
done
echo "ok"
# 执行结果
[root@ym test]# sh 1test.sh
1
2
3
4
5
ok
# 实例2:
[root@ym test]# cat 2test.sh
#!/bin/sh
while read line
do
echo "##########打印标准输入的内容##########"
echo "输出读到的一行内容:$line"
echo "##########重新开始读取标准输入内容####"
sleep 1
done
[root@ym test]# sh 2test.sh
hello shell
##########打印标准输入的内容##########
输出读到的一行内容:hello shell
##########重新开始读取标准输入内容####
hello world
##########打印标准输入的内容##########
输出读到的一行内容:hello world
##########重新开始读取标准输入内容####
hello python
##########打印标准输入的内容##########
输出读到的一行内容:hello python
##########重新开始读取标准输入内容####
8.4)、read :从标准输入读取字符信息,传给shell程序内部定义的变量
[root@ym ~]# read -p "Plase input your name:" name
Plase input your name:root
[root@ym ~]# echo $name
root
8.5)、shift :shift语句会改变位置参数,即 $1 $2 $3 会变成 $2 $3 重新排序参数位置。
[root@ym test]# cat test.sh
#!/bin/sh
echo $# # 获取传入的参数个数
shift
echo $* # 输出传输的所有参数
# 执行结果
[root@ym test]# sh test.sh -c python
2
python
8.6)、exit :退出shell程序,可以在 exit 后面指定一个数字作为状态码 1 - 255 范围
#! /bin/bash
if [ $# -ne 1 ] #如果传入参数个数等于1,则正常退出;否则非正常退出。
then
echo "args no!"
exit 123
else
echo "args ok!"
exit 0
fi
[root@ym ~]# sh test.sh
args no!
[root@ym ~]# echo $?
123
shell ( ) (( )) [ ] [[ ]] 用法
- 小括号()
- 命令组。括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格。
- 命令替换。等同于cmd,shell扫描一遍命令行,发现了$(cmd)结构,便将$(cmd)中的cmd执行一次,得到其标准输出,再将此输出放到原来命令。
- 用于初始化数组。如∶array=(a b c d)
- 双小括号 (())
- 整数扩展。这种扩展计算是整数型的计算,不支持浮点型。
- 只要括号中的运算符、表达式符合C语言运算规则.都可用在$((exp))中,甚至是三目运算符。
- 单纯用(())也可重定义变量值,比如 a=5;((a )) 可将 $a 重定义为6
- 常用于算术运算比较,双括号中的变量可以不使用$符号前缀。括号内支持多个表达式用逗号分开。for((i=0;i<5;i ))
- 单中括号 [ ] 、 双中括号 [[ ]]
- test <条件表达式> 等价于 [ <条件表达式> ] 语法结构
- [[ ]] 是拓展的 test 条件测试,可以使用 通配符等进行模式匹配,这是区别于其他几种的语法格式
- &&、||、>、< 等操作符可以使用与 双中括号[[ ]],不能用于单中括号[ ],在 [ ] 中一般使用 -a -o -gt lt
变量 |
描述 |
${var:-word} |
如果var存在且非null,返回它的值;否则返回word |
${var:=word} |
如果var存在且非null,返回它的值;否则将word赋值给var,并返回var的值 |
${var:?word} |
如果var存在且非null,返回它的值;否则显示var:?word |
${var: word} |
如果var存在且非null,返回word;否则返回null |
模式 |
描述 |
${variable#pattern} |
如果模式匹配于变量的开头处,则删除匹配的最短部分,并返回剩下的部分 |
${variable##pattern} |
如果模式匹配于变量的开头处,则删除匹配的最长部分,并返回剩下的部分 |
${variable%pattern} |
如果模式匹配于变量的结尾处,则删除匹配的最短部分,并返回剩下的部分 |
${variable%%pattern} |
如果模式匹配于变量的结尾处,则删除匹配的最长部分,并返回剩下的部分 |
注意:模式匹配处理字符串截取操作
- 这四种模式中都不会改变 variable 的值,其中,只有在 pattern 中使用了 * 匹配符号时,%和%%,# 和 ## 才有区别
- 结构中的 pattern 支持通配符如下:
- *:表示零个或多个任意字符
- ?:表示仅与一个任意字符匹配
- [...]:表示匹配中括号里面的字符
- [!...]: 表示不匹配中括号里面的字符
实例:${variable#pattern}
[root@ym ~]# var="/usr/share/doc/mysql-common/COPYING.Google"
[root@ym ~]# echo ${var#*/*n/}
COPYING.Google
实例:${variable##pattern}
[root@ym ~]# var="/usr/share/doc/mysql-common/COPYING.Google"
[root@ym ~]# echo $var
/usr/share/doc/mysql-common/COPYING.Google
[root@ym ~]# echo ${var##/*/}
COPYING.Google
实例:${variable%pattern}
[root@ym ~]# var="/usr/share/doc/mysql-common/COPYING.Google"
[root@ym ~]# echo ${var%/sh*}
/usr
实例:${variable%%pattern}
[root@ym ~]# var="/usr/share/doc/mysql-common/COPYING.Google"
[root@ym ~]# echo ${var%%s*}
/u
字符串操作:
[root@ym ~]# echo ${var%s*e} 从最右边删除最短匹配
testca
[root@ym ~]# echo $var
testcase
[root@ym ~]# echo ${var%%s*e} 从最右边删除最长匹配
te
[root@ym ~]# echo $var 变量没有改变
testcase
[root@ym ~]# echo ${var#?e} 从最左边删除最短匹配
stcase
[root@ym ~]# echo $var
testcase
[root@ym ~]# echo ${var#*e} 从最左边删除最短匹配
stcase
[root@ym ~]# echo $var
testcase
[root@ym ~]# echo ${var##*e} 从最左边删除最长匹配,即删除所有
[root@ym ~]# echo $var
testcase
[root@ym ~]# echo ${var##*s} 从最左边删除最长匹配
e
[root@ym ~]# echo $var
testcase
[root@ym ~]# echo ${var#test} 删除test
case
[root@ym ~]# echo $var
testcase
[root@ym ~]# echo ${var#tests} 没有匹配
testcase
Shell 基本运算符算术运算符
下表列出了常用的算术运算符,假定变量 a 为 10,变量 b 为 20:
算数 |
说明 |
实例 |
|
加法 |
expr $a $b 结果为 30。 |
- |
减法 |
expr $a - $b 结果为 -10。 |
* |
乘法 |
expr $a \* $b 结果为 200。 |
/ |
除法 |
expr $b / $a 结果为 2。 |
% |
取余 |
expr $b % $a 结果为 0。 |
= |
赋值 |
a=$b 将把变量 b 的值赋给 a。 |
== |
相等。用于比较两个数字,相同则返回 true。 |
[ $a == $b ] 返回 false。 |
!= |
不相等。用于比较两个数字,不相同则返回 true。 |
[ $a != $b ] 返回 true。 |
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:
运算符 |
说明 |
实例 |
-eq |
检测两个数是否相等,相等返回 true。 |
[ $a -eq $b ] 返回 false。 |
-ne |
检测两个数是否不相等,不相等返回 true。 |
[ $a -ne $b ] 返回 true。 |
-gt |
检测左边的数是否大于右边的,如果是,则返回 true。 |
[ $a -gt $b ] 返回 false。 |
-lt |
检测左边的数是否小于右边的,如果是,则返回 true。 |
[ $a -lt $b ] 返回 true。 |
-ge |
检测左边的数是否大于等于右边的,如果是,则返回 true。 |
[ $a -ge $b ]返回 false。 |
-le |
检测左边的数是否小于等于右边的,如果是,则返回 true。 |
[ $a -le $b ] 返回 true。 |
下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:
运算符 |
说明 |
实例 |
! |
非运算,表达式为 true 则返回 false,否则返回 true。 |
[ ! false ] 返回 true。 |
-o |
或运算,有一个表达式为 true 则返回 true。 |
[ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a |
与运算,两个表达式都为 true 才返回 true。 |
[ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:
运算符 |
说明 |
实例 |
&& |
逻辑的 AND |
[[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| |
逻辑的 OR |
[[ $a -lt 100 || $b -gt 100 ]] 返回 true |
下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:
运算符 |
说明 |
实例 |
= |
检测两个字符串是否相等,相等返回 true。 |
[ $a = $b ] 返回 false。 |
!= |
检测两个字符串是否相等,不相等返回 true。 |
[ $a != $b ] 返回 true。 |
-z |
检测字符串长度是否为0,为0返回 true。 |
[ -z $a ] 返回 false。 |
-n |
检测字符串长度是否为0,不为0返回 true。 |
[ -n "$a" ] 返回 true。 |
$ |
检测字符串是否为空,不为空返回 true。 |
[ $a ] 返回 true。 |
文件测试运算符用于检测 Unix 文件的各种属性。
属性检测描述如下:
操作符 |
说明 |
实例 |
-b file |
检测文件是否是块设备文件,如果是,则返回 true。 |
[ -b $file ] 返回 false。 |
-c file |
检测文件是否是字符设备文件,如果是,则返回 true。 |
[ -c $file ] 返回 false。 |
-d file |
检测文件是否是目录,如果是,则返回 true。 |
[ -d $file ] 返回 false。 |
-f file |
检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 |
[ -f $file ] 返回 true。 |
-g file |
检测文件是否设置了 SGID 位,如果是,则返回 true。 |
[ -g $file ] 返回 false。 |
-k file |
检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 |
[ -k $file ] 返回 false。 |
-p file |
检测文件是否是有名管道,如果是,则返回 true。 |
[ -p $file ] 返回 false。 |
-u file |
检测文件是否设置了 SUID 位,如果是,则返回 true。 |
[ -u $file ] 返回 false。 |
-r file |
检测文件是否可读,如果是,则返回 true。 |
[ -r $file ] 返回 true。 |
-w file |
检测文件是否可写,如果是,则返回 true。 |
[ -w $file ] 返回 true。 |
-x file |
检测文件是否可执行,如果是,则返回 true。 |
[ -x $file ] 返回 true。 |
-s file |
检测文件是否为空(文件大小是否大于0),不为空返回 true。 |
[ -s $file ] 返回 true。 |
-e file |
检测文件(包括目录)是否存在,如果是,则返回 true。 |
[ -e $file ] 返回 true。 |
-L file |
检测文件是否存在且是一个 链接文件,如果是,则返回true。 |
[ -L $file ] 返回 true。 |
-S file |
检测文件是否存在且是一个socket文件,如果是,则返回true。 |
[ -S $file ] 返回 true。 |
file1 -nt file2 |
检测file1 是否比file2新,如果是,则返回true |
[ file1 -nt file2 ]返回 true。 |
file1 -ot file2 |
检测file1 是否比file2 旧,如果是,则返回true |
[ file1 -nt file2 ]返回 true。 |
file1 -ef file 2 |
检测file1 是否和file2 是同一个文件,如果是,则返回true |
[ file1 -nt file2 ]返回 true。 |
#第一种语法:
if <条件表达式>
then
command 指令
fi
#第二种语法:
if <条件表达式>;then
command 指令
fi
2)、双分支条件判断
if <条件表达式>
then
command 1
else
command 2
fi
3)、多分支条件判断
if <条件表达式>
then
command1
elif <条件表达式>
then
command2
elif <条件表达式>
then
command3
eles
command4
fi
4)、条件判断嵌套语法
#1、 test 条件表达式
if test 表达式
then
command
fi
#2、 []条件表达式
if [字符集或算术表达式]
then
command
fi
#3、 [[]] 条件表达式
if [[条件表达式]]
then
command
fi
#4、 (())条件表达式
if((算术表达式))
then
command
fi
#5、 if 命令
then
command
fi
5)、使用脚本发送电子邮件
通过Linux服务器客户端发送邮件及配置
需要修改:
vim /etc/mail.rc
set from=1350115xxx@163.com smtp=smtp.163.com
set smtp-auth-user=13501157xxx@163.com smtp-auth-password=1qaz2wc smtp-auth=login
注意:如果是163邮箱,需要设置邮箱的一个授权码,将授权吗写入smtp-auth-password,否则发送不了邮件
邮件测试
echo "this is a test" | mail -s "标题" 13501157xxx@163.com
for 有限循环for训话语法格式:
#for 变量 in 要赋予的值
#do
# command1-N
#done
for 循环获取变量值
#for i in 1 2 3 4 5
#for i in I don"'"t know if this"'"ll work
#for i in `ls /tmp`
#for i in `cat file`
#IFS=$':'(指定分隔符)
#for i in `head -1 /etc/passwd`
#do
# echo "word:$i"
#done
for 循环 c 语言的写法
#for (( i=0; i<10; i ))
# do
# echo $i
#done
#for (( a=0 b=9;a<10 b>=0;a=a 2 b=b-2 ))
#do
# echo $a $b
#done
for 循环获取变量方式
#for i in /tmp/*
#for i in `ls /tmp`
do
# if [ -f /tmp/$i ]
# then
# echo "$i is file"
# else
# echo "$i is folder"
# fi
#done
for 循环练习
# 使用循环计算1到100之间的和
sum=0
for ((i=0;i<=100;i ))
do
#let sum =$i
#((sum =$i))
#sum=$[ $sum $i ]
#sum=$(expr $sum $i )
done
echo $sum
while 循环语法格式
# 语法格式:
#while [ 条件 ] 条件为真
#do
# command
#done
# while 常用的方法
#while [ 1 -eq 1 ]
#while true
#while :
#until false
#until :
#do
# date %S
# sleep 1
#done
while 嵌套if条件判断
#while :
# do
# A=`date %S`
# if [ $A -gt 55 ]
# then
# exit
# fi
# echo $A
# sleep 1
#done
while 嵌套for循环
#while :
# do
# A=`date %S`
# for i in `seq 10 -1 1`
# do
# expr $A $i
# sleep 1
# done
#sleep 1
#done
循环自增变量
- 循环自增变量
- i=expr $i 1;
- let i =1;
- ((i ));
- i=$[$i 1];
- i=$(( $i 1 ))
- 实例
#!/bin/bash
i=0;
while [ $i -lt 4 ];
do
echo $i;
i=`expr $i 1`;
# let i =1;
# ((i ));
# i=$[$i 1];
# i=$(( $i 1 ))
done
until 循环(条件不成立循环)
- until 循环执行一系列命令直至条件为 true 时停止。
- until 循环与 while 循环在处理方式上刚好相反。
- 一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。
until condition
do
command
done
- break 命令不执行当前循环体内break下面的语句从当前循环退出.
- continue 命令是程序在本循体内忽略下面的语句 从循环头开始执行
实例:
for i in `seq 1 10`
do
if [ $i -eq 5 ]
then
# break
continue
fi
echo $i
done
case语句case语句的语法格式:
case $VARAIBLE in
PAT1)
分支1
;;
PAT2)
分支2
;;
...
*)
分支n
;;
esac
注意: case支持glob风格的通配符: *:任意长度的任意字符; ?:任意单个字符; []:范围内任意单个字符; a|b:a或b;
显示一个脚本服务菜单cpu) display cpu information
mem) display memory information
disk) display disks information
quit) quit
要求:(1) 提示用户给出自己的选择;
(2) 正确的选择则给出相应的信息;否则,则提示重新选择正确的选项;
#!/bin/bash
#
cat << EOF
cpu) display cpu information
mem) display memory infomation
disk) display disks information
quit) quit
===============================
EOF
read -p "Enter your option: " option
while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ]; do
echo "cpu mem disk quit"
read -p "Enter your option again: " option
done
if [ "$option" == "cpu" ]; then
lscpu
elif [ "$option" == "mem" ]; then
free -m
elif [ "$option" == "disk" ]; then
fdisk -l /dev/[hs]d[a-z]
else
echo "quit"
exit 0
fi
Array数组什么是数组array
- shell数组就是一个元素的集合,它有限个数的元素(变量和字符内容),用一个名字来命名,用下标进行区分,这个名字就称为数组名,组成数组的变量称之为数组元素
- 使用数组可以缩短和简化程序开发
第一种方法:
array=(value1 value2 value3......)
第二种方法:
array=([1]=one [2]=two [3]=three) # 通过指定下标的方式定义数组
array=(1 2 3)
# 查询数组所有元素
echo ${array[*]}
# 显示数组的第一个元素
echo ${array[1]}
# 动态获取数组
array=($(command))
# 打印数组的所有元素
echo ${array[*|@]}
# 获取数组的元素个数
echo ${#array[*|@]}
#数组的赋值
array[3]=four
# 数组的删除
unset array[1]
# 数组内容的截取和替换
array=(1 2 3)
echo ${array[@]:1:3}
echo ${array[@]/1/b}
select 循环菜单
- select也是循环的一种,它比较适合用在用户选择的情况下。
select 变量名 [in 菜单取值列表]
do
命令集
done
#!/bin/bash
fruits=(
"add"
"del"
"select"
"watermelon"
)
PS3="please select a num from menu:" # 命令提示符
echo "Please guess which fruit I like :"
select var in ${fruits[@]} # ${fruits} 获取数组值
do
if [ $var = "add" ]; then
echo "Congratulations you are my good firend!"
break
else
echo "Try again!"
fi
done
Function 函数函数的定义
- Shell 函数的本质是一段可以重复使用的脚本代码,这段代码被提前编写好了,放在了指定的位置,使用时直接调取即可。
Shell 函数定义的语法格式如下:
function name() {
statements
[return value]
}
对各个部分的说明:
- function是 Shell 中的关键字,专门用来定义函数;
- name是函数名;
- statements是函数要执行的代码,也就是一组语句;
- return value表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写。
由{ }包围的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码。
name() {
statements
[return value]
}
函数调用
调用 Shell 函数时可以给它传递参数,也可以不传递。如果不传递参数,直接给出函数名字即可:
name
如果传递参数,那么多个参数之间以空格分隔:
name param1 param2 param3
不管是哪种形式,函数名字后面都不需要带括号。
和其它编程语言不同的是,Shell 函数在定义时不能指明参数,但是在调用时却可以传递参数,并且给它传递什么参数它就接收什么参数。
Shell 也不限制定义和调用的顺序,你可以将定义放在调用的前面,也可以反过来,将定义放在调用的后面。
函数的返回值 return函数的执行结果返回值:(1) 使用echo或printf命令进行输出; (2) 函数体中调用的命令的执行结果; 函数的退出状态码 1 - 255: (1) 默认取决于函数体中执行的最后一条命令的退出状态码; (2) 自定义:return
实例:添加10个用户,添加用户的功能使用函数实现,用户名作为参数传递给函数;
#!/bin/bash
# 5: user exists
addusers() {
if id $1 &> /dev/null; then
return 5
else
useradd $1
retval=$?
return $retval
fi
}
for i in {1..10}; do
addusers ${1}${i}
retval=$?
if [ $retval -eq 0 ]; then
echo "Add user ${1}${i} finished."
elif [ $retval -eq 5 ]; then
echo "user ${1}${i} exists."
else
echo "Unkown Error."
fi
done