脚本类似批处理,简单来讲就是把许多的指令集合在一起,并提供循环、条件、判断等重要功能,语法简单实用,用以编写程序,大大简化管理员的操
作,并可以完成图形工具所无法实现的功能:自动化运维。而为脚本的优点很明显:避免不必要的错误;节省时间
一‘脚本的基本写法:
[root@mail-qq mnt]# vim test.sh
[root@mail-qq mnt]# cat test.sh
#!/bin/bash //写脚本的环境,
echo hello word //脚本具体将要执行的命令
环境一共有下面6种
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
二、脚本有两种方法可以执行:
1. sh 跟脚本的名称
[root@mail-qq mnt]# sh test.sh
hello word
2.给x权限,即执行权限:
[root@mail-qq mnt]# chmod +x test.sh
[root@mail-qq mnt]# /mnt/test.sh //脚本的绝对路径
hello word
三、变量($)
[root@mail-qq mnt]# sh test.sh
LOCAL USER is root
[root@mail-qq mnt]# cat test.sh
#!/bin/bash
NAME="LOCAL USER is"
echo $NAME $USER
[root@mail-qq mnt]# vim test.sh
[root@mail-qq mnt]# sh test.sh
LOCAL USER is root
my name is student_DUCK
[root@mail-qq mnt]# cat test.sh
#!/bin/bash
NAME="LOCAL USER is"
echo $NAME $USER
FIRSTNAME=student
FAMNAME=DUCK
echo my name is ${FIRSTNAME}_$FAMNAME
[root@mail-qq mnt]# echo $a
1
[root@mail-qq mnt]# echo $a0
[root@mail-qq mnt]# echo ${a}0 //变量和其他字符组合使用时需要用{}将变量括起来!!!!!
10
[root@mail-qq mnt]# vim test.sh
[root@mail-qq mnt]# sh test.sh
LOCAL USER is root
my name is student_DUCK
TIME is Tue Apr 25 07:28:19 EDT 2017
[root@mail-qq mnt]# cat test.sh
#!/bin/bash
NAME="LOCAL USER is"
echo $NAME $USER
FIRSTNAME=student
FAMNAME=DUCK
echo my name is ${FIRSTNAME}_$FAMNAME
TIME=$(date)
echo TIME is $TIME
四、四则运算以及计算的几种命令:
- 减法
+ 加法
** 幂运算
* 乘法
/ 除法
% 余数
方法1:[]表示计算
[root@mail-qq mnt]# echo $[1+2] + 加法
3
[root@mail-qq mnt]# echo $[5-4] -减法
1
[root@mail-qq mnt]# echo $[5*4] *乘法
20
[root@mail-qq mnt]# echo $[2**10] *幂运算
1024
ot@mail-qq mnt]# echo $[24/6] /除法
4
[root@mail-qq mnt]# echo $[10%3] %取余 结果显示余数:10除3等余3,余1,所以结果为1
1
方法2:expr
[root@mail-qq mnt]# echo `expr 2 \* 3`
6
[root@mail-qq mnt]# echo `expr 10 \% 3`
1
[root@mail-qq mnt]# echo `expr 10 \/ 3`
3
[root@mail-qq mnt]# echo `expr 10 \+ 3`
13
[root@mail-qq mnt]# echo `expr 10 \- 3`
7
凡方法3: let
[root@mail-qq mnt]# let A=1+2
[root@mail-qq mnt]# echo $A
3
[root@mail-qq mnt]# let C=2*10
[root@mail-qq mnt]# echo $C
20
[root@mail-qq mnt]# let D=2**10
[root@mail-qq mnt]# echo $D
1024
<VARIABLE>++ 增量后
<VARIABLE>-- 减量后
+= 加等
-= 减等
[root@mail-qq mnt]# vim 2test.sh
[root@mail-qq mnt]# sh 2test.sh
1
2
3
4
5
6
7
8
9
10
[root@mail-qq mnt]# cat 2test.sh
#!/bin/bash
for ((i=1;i<=10;i++))
do
echo $i
done
例:+=
[root@mail-qq mnt]# vim 4test.sh
[root@mail-qq mnt]# sh 4test.sh
1
3
6
10
15
21
28
36
45
[root@mail-qq mnt]# cat 4test.sh
#!/bin/bash
for ((i=1;i<10;i++))
do
((j+=i))
echo $j
done
五、引用和转义
引用和转义在shell解析字符串时用于去除字符串中特殊字符或保留词语的特殊含义。这会导致按字
面处理字符串,而不是展开变量或将其部分内容视作具有特殊含义。
引用有三种类型:
弱引用
将字符串放置在双引号中,保留字符串中所有字符的文字值,$、`、\和!字符除外。换言之,变量
扩展和命令扩展在双引号内仍起作用。
echo “can I have a $FRUIT”
echo “The current time is $(date +%r).”
强引用
将字符串放置在单引号中,保留字符串中所有字符的文字值,同时禁用所有扩展:
echo “Make $$$ Fast”
rm 'untitled folder'
转义
非引用的\是转义字符。它保留了下一个字符的文字值。(例如,\$PATH是确切的字符串$PATH,而
不是PATH变量的内容。)
六、运算和逻辑运算常用符:
-lt 小于
-le 小于等于
-gt 大于
-ge 大于等于
-eq 等于
-ne 不等于
逻辑运算符:-o -a ! && ||
-a 并列关系
-o 选择关系
! 取反,例如:=等于 != 不等于
&& 如果条件成功
|| 如果条件失败
七、经典练习
经典练习1:写脚本执行后显示/etc/下文件是否村在:
[root@mail-qq mnt]# vim find_file.sh
[root@mail-qq mnt]# sh find_file.sh
/etc/hello is not exist
/etc/passwd/ is not exist
/etc/group is exist
[root@mail-qq mnt]# cat find_file.sh
#!/bin/bash
for NAME in /etc/hello /etc/passwd/ /etc/group
do
ls -l $NAME &>/dev/null && echo $NAME is exist ||echo $NAME is not exist
done
经典练习2:
[root@mail-qq mnt]# sh test.sh
LOCAL USER is root
[root@mail-qq mnt]# cat test.sh
#!/bin/bash -x
NAME="LOCAL USER is"
echo $NAME $USER
// 因为$USER是系统自定的变量,所以执行脚本之后就可以显示当前用户。
[root@mail-qq mnt]# echo $USER
root
经典练习3:
[root@mail-qq mnt]# vim test.sh
[root@mail-qq mnt]# sh test.sh
LOCAL USER is root
my name is lee_DUCK
TIME is Wed Apr 26 22:34:14 EDT 2017
[root@mail-qq mnt]# cat test.sh
#!/bin/bash
NAME="LOCAL USER is"
echo $NAME $USER
FIRSTNAME=lee
FAMNAME=DUCK
echo my name is ${FIRSTNAME}_$FAMNAME //变量跟别的字符组合使用时,需要用大括号括起来
TIME=$(date)
echo TIME is $TIME FIRSTNAME 和TIME都是变量,FIRSTNAME=后面是具体的字符,所以不用$(),
TIME=后面之执行的是date命令,所以要$()
经典练习4:显示自己主机的IP (只显示自己的IP)
[root@mail-qq mnt]# sh show_ip.sh
mail-qq.qq.com's ip is : 172.25.254.195
[root@mail-qq mnt]# cat show_ip.sh
#!/bin/bash
IP=`ifconfig eth0 | grep inet | grep inet | grep inet6 -v | awk -F " " '{print $2}'`
HOSTNAME=`hostname`
echo "${HOSTNAME}'s ip is : $IP"
经典练习5:显示2到10之间的数字,以2为单位递增。
[root@mail-qq mnt]# sh number.sh
2
4
6
8
10
[root@mail-qq mnt]# cat number.sh
#!/bin/bash
for NUM in $( seq 2 2 10 ) //显示从2开始以2为单位递增到10
do
echo $NUM
done
[root@mail-qq mnt]# sh number.sh
3
5
7
9
[root@mail-qq mnt]# cat number.sh
#!/bin/bash
for NUM in $( seq 3 2 10 ) //显示从3开始以2为单位递增到10
do
echo $NUM
done
经典练习6:检查主机IP为172.25.254.1到172.25.254.40的主机是否开启,如果开启显示up,如果关闭显示down
[root@mail-qq mnt]# sh status_ip.sh
172.25.254.1 is down
172.25.254.2 is down
172.25.254.3 is down
172.25.254.4 is up
172.25.254.5 is down
……
[root@mail-qq mnt]# cat status_ip.sh
#!/bin/bash
for NUM in 172.25.254.{1..40}
do
if
ping -c1 -w1 $NUM &>/dev/null //-w1 表示每秒执行一次ping命令
then
echo $NUM is up
else
echo $NUM is down
fi
done
经典练习7:将/mnt/userfile里面的内容每一行当作一个用户名建立用户。
[root@mail-qq mnt]# vim userfile
[root@mail-qq mnt]#cat userfile
user1 user2 user3
[root@mail-qq mnt]# cat create_user.sh
#!/bin/bash
MAX=`wc -l /mnt/userfile | cut -d " " -f 1` //找到/mnt/userfile的最大行,给到MAX
for NUM in `seq 1 $MAX` //从1到MAX 逐个递增
do
NAME=`sed -n ${NUM}p /mnt/userfile` //从userfile的第一行逐行给到NAME
useradd $NAME //新建用户
done //for语句的结束
[root@mail-qq mnt]# sh create_user.sh
延伸1、:查看脚本运行之后产生的变化,查看用户是否已经建立
[root@mail-qq mnt]# cat /etc/passwd | grep bash | cut -d ":" -f 1 //显示所有存在的用户
root
student
natasha
user1
user2
user3
经典练习8:将/mnt/userfile里面的内容每一行当作一个用户名建立用户,并将/mnt/passfile里的每一行对应给到对应用户作为密码
[root@mail-qq mnt]# sh create_user.sh userfile passfile //必须跟脚本涉及的两个文件(行数相同)
[root@mail-qq mnt]# cat create_user.sh
#!/bin/bash
MAX=`wc -l $1 | cut -d " " -f 1`
for NUM in `seq 1 $MAX`
do
NAME=`sed -n ${NUM}p $1`
PASS=`sed -n ${NUM}p $2`
useradd $NAME
echo $PASS|passwd --stdin $NAME
done
经典练习9:做一个1分30秒的倒计时:
[root@mail-qq mnt]# cat power_time.sh
#!/bin/bash
MIN=1
for ((i=3;i>=0;i--))
do
while
[ "$i" -eq "0" -a "$MIN" -gt "0" ]
do
echo -n "After ${MIN}:${i} is end "
echo -ne "\r" //光标移动到行首,并显示新的结果。
i=59
sleep 1
((MIN--))
done
echo -n "After ${MIN}:${i} is end "
echo -ne "\r"
sleep 1
done
经典练习10:建立用户。如果输入的用户存在,报错。如果用户不存在 执行建立用户。
[root@mail-qq mnt]# sh check_create.sh
please input username :user4
[root@mail-qq mnt]# cat /etc/passwd | grep bash | cut -d ":" -f 1
root
student
user1
user2
user3
user4
[root@mail-qq mnt]# sh check_create.sh
please input username :user4
Error: user is alredy exsit
[root@mail-qq mnt]# sh check_create.sh
please input username :user5
[root@mail-qq mnt]# cat /etc/passwd | grep bash | cut -d ":" -f 1
root
student
user1
user2
user3
user4
user5
[root@mail-qq mnt]# cat check_create.sh
#!/bin/bash
read -p "please input username :" USERNAME //显示请输入用户名称,输入后执行后续操作。
CHECK=`getent passwd $USERNAME` //判断用户是否存在。
if //进入循环
[ -z "$CHECK" ] //“-z”表示为空,
then
useradd $USERNAME
else
echo "Error: user is alredy exsit"
fi //结束循环
经典练习11:用userfile里面的每一行作为用户名建立用户并将passfile里面的每一行,作为密码依次给到每个用户。
[root@mail-qq mnt]# sh user_create.sh userfile passfile
ERROR: user1 is already exsit
ERROR: user2 is already exsit
ERROR: user3 is already exsit
[root@mail-qq mnt]# vim userfile
[root@mail-qq mnt]# sh user_create.sh userfile passfile
Creating mailbox file: File exists
Changing password for user user4.
passwd: all authentication tokens updated successfully.
Creating mailbox file: File exists
Changing password for user user5.
passwd: all authentication tokens updated successfully.
Creating mailbox file: File exists
Changing password for user user6.
passwd: all authentication tokens updated successfully.
[root@mail-qq mnt]# cat /etc/passwd | grep bash | cut -d ":" -f 1
root
student
user1
user2
user3
user4
user5
user6
[root@mail-qq mnt]# cat user_create.sh
#!/bin/bash
if
[ -n "$1" -a -n "$2" ]
then
MAX_USER=`wc -l $1 | cut -d " " -f 1`
MAX_PASS=`wc -l $1 | cut -d " " -f 1`
if
[ "$MAX_USER" -eq "$MAX_PASS" ]
then
for NUM in `seq 1 $MAX_USER`
do
USERNAME=`sed -n ${NUM}p $1`
PASSWORD=`sed -n ${NUM}p $1`
CHECK=`getent passwd $USERNAME`
if
[ -z "$CHECK" ]
then
useradd $USERNAME
echo $PASSWORD | passwd --stdin $USERNAME
else
echo "ERROR: $USERNAME is already exsit"
fi
done
else
echo " ERROR:diffrent lines of two files"
fi
else
echo "ERROR:there is lack of files ,Please check"
fi
延伸2、:$? 和!的用法
$? , != 的用法,
echo $? 输出的结果为:正确输出为0,不正确输出结果不为0
[root@mail-qq mnt]# [ 2 = 2 ]; echo $?
0
[root@mail-qq mnt]# [ 1 = 2 ]; echo $?
1
[root@mail-qq mnt]# [ 1 = 2 ] echo $?
-bash: [: missing `]'
[root@mail-qq mnt]# [ 1 = 2 ] ; echo $?
1
[root@mail-qq mnt]# [ 1 = 1 ] ; echo $?
0
!=表示不等于。
[root@mail-qq mnt]# [ 1 != 1 ] ; echo $?
1
[root@mail-qq mnt]# [ 2 != 1 ] ; echo $?
0
经典练习12:脚本后面跟一个数,如果是10以内的显示0~10 ,如果不是显示not0~10
[root@mail-qq mnt]# sh number_check.sh
Please input a number : 9
9 is 0~10
[root@mail-qq mnt]# sh number_check.sh
Please input a number : 50
50 is not 0~10
[root@mail-qq mnt]# sh number_check.sh 5
5 is 0~10
[root@mail-qq mnt]# sh number_check.sh -5
-5 is not 0~10
[root@mail-qq mnt]# cat number_check.sh
#!/bin/bsah
if
[ -n "$1" ]
then
if
[ "$1" -ge "0" -a "$1" -le "10" ]
then
echo "$1 is 0~10"
else
echo "$1 is not 0~10"
fi
else
read -p "Please input a number : " NUMBER
if
[ "$NUMBER" -ge "0" -a "$NUMBER" -le "10" ]
then
echo "$NUMBER is 0~10"
else
echo "$NUMBER is not 0~10"
fi
fi
test 或 [ ] 的一些参数:
-e 存在 (exist)
-b 是区(block)
-f 是常规的文件(file)
-d 是目录(directory)
-h -L 是链接(link)
[root@mail-qq mnt]# [ -f /etc/passwd ]; echo $?
0
[root@mail-qq mnt]# [ -d /etc/passwd ]; echo $?
1
[root@mail-qq mnt]# [ -d /etc ]; echo $?
0
[root@mail-qq mnt]# [ -b /dev/vdb ]; echo $?
0
[root@mail-qq mnt]# [ -e /etc/passwd ]; echo $?
0
经典练习13:脚本后面如果跟apple显示banana,如果是banana显apple,如果是其他字符显示i don't know
此处要用case 语句 !!!!!
[root@mail-qq mnt]# sh friut_check.sh apple
banana
[root@mail-qq mnt]# sh friut_check.sh banana
apple
[root@mail-qq mnt]# sh friut_check.sh peanut
I don't know
[root@mail-qq mnt]# cat friut_check.sh
#!/bin/bash
case "$1" in
apple)
echo banana
;;
banana)
echo apple
;;
*)
echo "I don't know"
esac
经典练习14:用[ ] 检查所给对象的类型是否与参数匹配,如果匹配显示对象就是参数代表的类型,如果不匹配显示对象不是参数代表的类型,其他情况显示unknow type
此处用到函数 !!!!!!!!!!
[root@mail-qq mnt]# vim file_check.sh
[root@mail-qq mnt]# sh file_check.sh -f /etc/passwd
/etc/passwd is a file
[root@mail-qq mnt]# sh file_check.sh -f /etc/
/etc/ is not a file
[root@mail-qq mnt]# sh file_check.sh -d /etc
/etc is a directory
[root@mail-qq mnt]# sh file_check.sh -d /etc/passwd
/etc/passwd is not a directory
[root@mail-qq mnt]# sh file_check.sh -b /dev/vdb
/dev/vdb is a block
[root@mail-qq mnt]# sh file_check.sh -b /dev/
/dev/ is not a block
[root@mail-qq mnt]# sh file_check.sh -b
block is not a
[root@mail-qq mnt]# sh file_check.sh
unknown type
[root@mail-qq mnt]# sh file_check.sh -b c
c is not a block
[root@mail-qq mnt]# cat file_check.sh
#!/bin/bash
CHECK () { //声明函数的名字:CHECK,()和{}为函数的格式
if //用到if语句,
[ $1 $2 ] //用到test[] 这个命令作为工具,例如:[ -f /etc/passwd ]
then 其中$1为 -f -b -d 等参数,是函数的第一个变量,也是脚本后面
echo $2 is a $3 跟的第一个变量;$2为需要CHECK的对象,是函数的第二个变量,也是
else 脚本后面跟的第二变量,$3为 是函数的第三个变量。是下面case里面的
echo $2 is not a $3 file 或者block 或者 directory。
fi
}
case "$1" in
-f)
CHECK -f $2 file
;;
-b)
CHECK -b $2 block
;;
-d)
CHECK -d $2 directory
;;
*)
echo " unknown type "
esac
expect语句
在shell中利用expect实现自动应答脚本
[root@mail-qq mnt]# yum install expect -y //安装expect软件包
经典练习15:
[root@mail-qq mnt]# /mnt/answer.exp
spawn /mnt/ask.sh
input your name : xiaoyao
input your age : 26
input your calss : linux
xiaoyao is 26's old and xiaoyao is linux student
[root@mail-qq mnt]# cat ask.sh
#!/bin/bash
read -p "input your name : " NAME
read -p "input your age : " AGE
read -p "input your calss : " CLASS
echo $NAME is $AGE\'s old and $NAME is $CLASS student
[root@mail-qq mnt]# cat answer.exp
#!/usr/bin/expect
spawn /mnt/ask.sh
expect "name :"
send "xiaoyao\r"
expect "age :"
send "26\r"
expect "class :"
send "linux\r"
expect eof //执行后退出执行后的界面。
经典练习16:写即脚本,实现自动连接远程主机。
[root@mail-qq mnt]# mv ssh_95.exp ssh_215.exp
[root@mail-qq mnt]# /mnt/ssh_215.exp
spawn ssh root@172.25.254.215
root@172.25.254.215's password:
Last login: Fri Apr 28 02:48:32 2017 from 172.25.254.195
[root@mail-westos ~]#
[root@mail-qq mnt]# cat ssh_215.exp
#!/usr/bin/expect
spawn ssh root@172.25.254.215 //直接调用命令
expect {
"(yes/no)?" { send "yes\r";exp_continue}
"password:" { send "redhat\r"};
}
interact //动作执行后留在执行后的界面,
连接后可以在远程主机上操作,