shell脚本
· 可以运行的文本文件,可以实现某种功能。
· 提前设计可执行语句,用来完成特定任务的文件;
· 将命令都写入到文本文件(命令的堆积),然后赋予文本文件以可执行权限;
· 文件名以.sh结尾;
shell脚本的优势:
· 将重复的任务流程化;
· 将复杂的任务简单化;
· 将人工干预的任务自动化;
非交互式shell脚本:
· 需要提前设计、智能化难度大;
· 批量执行、效率高;
· 方便在后台静默运行;
规范的shell脚本的一般组成:
· #!环境声明(声明下边的可执行代码用什么程序翻译)
· 以#开头的是注释行,不会执行
· 可执行代码
· 实例:
]# vim /root/hello.sh
#!/bin/bash #环境声明,下边的命令用bash执行
# 以#开头的行是注释行,不会执行 #注释
# 下边的是可执行代码
echo "Hello World!" #可执行代码
#切换到末行模式
:wq #保存并退出
]# chmod +x /root/hello.sh #添加可执行权限
]# /root/hello.sh #以绝对路径执行脚本文件
管道:
· 使用 " | "符号 作为管道操作
· 将 | 前一条命令的标准输出交给后一条命令处理
[root@shell ~]# cat /etc/passwd | grep "root" #将cat后的passwd文件交给后边的grep命令处理
root:x:0:0:root:/root:/bin/bash
重定向:
** · 输出重定向**
- 将输出重定向到 屏幕 或设备 或文件
> :只收集前面命令的 正确输出,将其正确输出写入文本文件
2> :只收集前面命令的 错误输出,将其错误输出写入文本文件
&> :收集前面命令的 正确&错误输出,将正确&错误 输出写入文本文件
>&2 :收集前面命令的输出指定为错误输出,配合【exit 非0值】使用
[root@shell ~]# echo "hello world" > /1.txt
[root@shell ~]# cat /1.txt /etc/ > /a.txt #收集正确输出
cat: /etc/: Is a directory
[root@shell ~]# cat /a.txt #文件中只有正确的输出信息
hello world
[root@shell ~]# cat /1.txt /etc/ 2> /a.txt #收集错误输出
hello world
[root@shell ~]# cat /a.txt #文件中只有错误输出
cat: /etc/: Is a directory
[root@shell ~]# cat /1.txt /etc &> /a.txt #收集正确和错误输出
[root@shell ~]# cat /a.txt #文件中有正确和错误的输出
hello world
cat: /etc: Is a directory
[root@test ~]# vim test.sh
echo "我错了" >&2 #将输出指定为错误输出
exit 1 #将退出码设置为1,默认正确退出码为0
[root@test ~]# chmod +x test.sh
[root@test ~]# ./test.sh
[root@test ~]# echo $?
1 #上调命令为错误输出
** ·输入重定向**
[root@test ~]# cat > /a.txt <<EOF
> 此处写入cat的文本,重定向输入给/a.txt
> <<表示接受一个输入结束的标识,当在行首输入这个标识后,会结束输入
> EOF
[root@test ~]# cat /a.txt
此处写入cat的文本,重定向输入给/a.txt
<<表示接受一个输入结束的标识,当在行首输入这个标识后,会结束输入
黑洞设备:
· /dev/null
· 专门收集无用的输出信息,使用后屏幕不再显示相关提示信息
[root@test ~]# ls / #ls正常显示输出
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
[root@test ~]# ls / &> /dev/null #将ls的输出写入黑洞
#屏幕没有任何输出
变量:
** · 什么是变量**
- 以不变的名称存放可能会变化的值;
- 方便以固定名称重复使用某个值;
- 提高对任务需求、运行环境变化的适应能力;
- 为了增加脚本适应多变的环境、多变的需求、使用方便性,所以需要使用变量;
** · 变量的基本格式**
- 赋值: 变量名=变量值
- 引用: $变量名
- 查看: ]# echo $变量名; echo ${变量名} #使用 ${} 是为了断开变量名与其他字符混合,造成变量不存在
** · 设置变量时的注意事项**
- 若指定的变量名已存在,相当于为此变量重新赋值。 ]# a=10; a=15; echo $a ==> 15
- 等号两边不能有空格。
- 变量名只能由字母、数字、下划线组成,区分大小写。 ]# a_1=1; A=1
- 变量名不能以数字开头,不要使用关键字和特殊字符
环境变量
· USER :储存当前登陆的用户
[root@shell2 ~]# echo $USER #显示$USER的变量值
root
[root@shell2 ~]# useradd testuser #创建一个测试用户
[root@shell2 ~]# su - testuser #切换到测试用户
[testuser@shell2 ~]$ echo $USER #显示当前的用户
testuser
位置变量
· 在执行脚本时提供的默认命令行参数
· 格式: ]# 脚本.sh $1 $2 $3 ...
[root@shell2 ~]# vim shell1.sh
#!/bin/bash
echo $1
echo $2
echo $3
[root@shell2 ~]# chmod +x shell1.sh
[root@shell2 ~]# ./shell1.sh hh1 hh2 hh3
hh1
hh2
hh3
预定义变量
$# :输出已加载的位置变量的个数(即运行脚本时,在脚本后面写的参数数量)
$* :输出所有位置变量的值
$? :输出程序退出后的状态值,0表示正常,非0表示异常
[root@shell2 ~]# vim shell2.sh
#!/bin/bash
echo $1
echo $2
echo $3
echo $# #显示参数总个数
echo $* #显示所有参数值
[root@shell2 ~]# chmod +x shell2.sh
[root@shell2 ~]# ./shell2.sh aa bb cc dd ee
aa
bb
cc
5 # $#的输出
aa bb cc dd ee # $*的输出
[root@shell2 ~]# ping -c 2 127.0.0.1 # 发2个包,ping正常ip
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.058 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.025 ms
--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.025/0.041/0.058/0.017 ms
[root@shell2 ~]# echo $?
0
[root@shell2 ~]# ping -c 2 1.2.3.4 # 发2个包,瓶错误ip
PING 1.2.3.4 (1.2.3.4) 56(84) bytes of data.
--- 1.2.3.4 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 999ms
基本符号
$[] :运算,计算器。 ]# echo $[1+2] ==> 3
'' :单引号,让引号中间的特殊字符无效化,变为普通字符。 ]# echo '$a' ==> $a
$() | `` :$()或者反撇号,将命令的输出结果作为参数。 ]# mkdir $(data +%F) ==> 2019-01-22
[root@shell2 ~]# echo $[1+1]
2
[root@shell2 ~]# echo $[100%3] #取余运算
1
[root@shell2 ~]# echo "$?" #正常显示
0
[root@shell2 ~]# echo '$?' #作为输出显示
$?
[root@shell2 ~]# mkdir $(date +%F) #创建一个以日期为名的文件夹
[root@shell2 ~]# ll
drwxr-xr-x. 2 root root 6 Jan 22 22:13 2019-01-22
read命令
· 用途:产生交互的方式,将用户从键盘上的输入,赋予一个变量来存储。
· 选项:-p,书写屏幕输出信息
-n 数字,定义输入文本的长度
]# vim useradd.sh
#!/bin/bash
read -p "请输入要创建的用户名:" ming #交互式,收集用户输入赋值给变量ming
stty -echo #隐藏输入
read -p "输入用户密码:" mima
stty echo #显示输入
useradd $ming &>/dev/null
echo "用户 $ming 创建成功"
echo $mima | passwd --stdin $ming &>/dev/null #设置密码
echo "密码设置成功"
]# chmod +x useradd.sh
]# ./useradd.sh
测试命令表达式
语法:
]# [ 测试表达式 ]
]# echo $? (检查状态值)
选项:
·检查文档状态( ]# $[ 选项 路径 ] )
-e = 文档存在 为真
-d = 文档存在且是 目录 为真
-f = 文档存在且是 文件 为真
-r = 文档存在且有 读取权限 为真
-w = 文档存在且有 写入权限 为真
-x = 文档存在且有 执行权限 为真
·比较整数大小( ]# [ 值A 选项 值B ] )
-gt :(greater)大于
-ge :()大于等于
-eq :(equal)等于
-ne :(not equal)不等于
-le :()小于等于
-lt :(less-than)小于
·字符串比对( # [ $USER == root ] )
== : 相等为真
!= : 不等为真
判断字符串中是否包含另一字符串
[[ $a =~ "b" ]] : 判断变量中是否包含字符串(=~ 代表正则的匹配),变量a中是否包含字符b
分支结构
1.if结构:
if [ 测试条件 ];then
执行A
fi
2.if双分支结构:
if [ 测试条件 ];then
执行A
else
执行B
fi
3.if多分支结构:
if [ 测试条件1 ];then
执行A
elif [ 测试条件2 ];then
执行B
elif [ 测试条件3 ];then
执行C
elif...
执行...
else
执行Z
fi
例1:
# vim /root/suiji.sh #
/vim/
#!/bin/bash #
read -p '输入一个10以内的数字:' numIn #
num=$[ $RANDOM % 10 ] # $RANDOM=随机数。取余10(不含)以内的数字
if [ $numIn -eq $num ];then # 如果 [ 相等 ];然后
echo '答对了' #
else # 否则
echo '错了,正确数字是:'$num #
fi # 结束finish
/vim/
#chmod +x /root/suiji.sh #
# /root/suiji.sh #
例2:条件判断语法
1).如果a>b且a<c
if (( a > b )) && (( a < c )) 或者
if [[ $a > $b ]] && [[ $a < $c ]] 或者
if [ $a -gt $b -a $a -lt $c ] //-a,and 或者
if [[ $a > $b && $a < $c ]]
2).如果a>b或a<c
if (( a > b )) || (( a < c )) 或者
if [[ $a > $b ]] || [[ $a < $c ]] 或者
if [ $a -gt $b -o $a -lt $c ] //-o,or 或者
if [[ $a > $b || $a < $c ]]
for循环
for 变量名 in 值列表
do
执行命令块
done
[root@server0 ~]# cat /root/for.sh
#!/bin/bash
for i in zhangsan lisi wangwu dc haha xixi duanwu zhongqiu
do
useradd $i &> /dev/null
echo $i创建成功
done
[root@server0 ~]# cat /root/for.sh
#!/bin/bash
for i in $(cat /root/tarena.txt)
do
useradd $i &> /dev/null
echo $i创建成功
done