bash脚本编程
fgrep:不支持正则表达式
静态语言:编译型语言
强类型(变量) 关键字
事先转换成可执行格式
c\c++\JAVA\c#
动态语言:解释型语言
弱类型
边解释边执行
PHP\SHELL\python\perl
变量:内存空间、命名
内存:编址的存储单元
变量类型:事先确定数据的存储格式和长度
缓冲区溢出
bash变量类型:
环境变量
本地变量(局部变量)
位置变量
特殊变量
本地变量:
VARNAME=VALUE:作用域为整个bash进程
局部变量:
local VARNAME=VALUE:作用域为当前代码段
环境变量:作用域为当前shell进程及其子进程
export VARNAME=VALUE 或者
VARNAME=VALUE
export VARNAME
“导出”
脚本在执行时会启动一个子shell进程:
命令行中启动的脚本会继承当前shell环境变量
系统自动执行的脚本(非命令行启动)就需要自我定义需要各环境变量
bash
不同的shell是两个不同的shell进程
引用变量:${VARNAME},括号可以省略
#加{}的情况
[root@localhost ~]# ANIMAL=pig
[root@localhost ~]# echo "There are some $ANIMALs"#引用成新变量
There are some
[root@localhost ~]# echo "There are some ${ANIMAL}s"
There are some pigs
单引号是弱引用,不做变量替换:
[root@localhost ~]# echo "There are some ${ANIMAL}s"
There are some pigs
[root@localhost ~]# echo 'There are some ${ANIMAL}s'
There are some ${ANIMAL}s
pstree 看当前是否在子shell中
位置变量:
$1,$2…
特殊变量:
$?:上一个命令的执行状态返回值
程序执行,可能有两类返回值:
程序执行结果
程序状态返回代码(0-255)
0:正确执行
1-255:错误执行:1,2,127系统预留,其他可以自定义
[root@localhost ~]# ls /var
account cache db games kerberos local log nis preserve spool tmp
adm crash empty gopher lib lock mail opt run target yp
[root@localhost ~]# echo $?
0
[root@localhost ~]# lss /var
bash: lss: 未找到命令...
相似命令是: 'ls'
[root@localhost ~]# echo $?
127
输出重定向:
/dev/null/:软件模拟设备,bit bucket,数据黑洞
#用于命令结果对我们没有意义
[root@localhost ~]# id student &> /dev/null
[root@localhost ~]# echo $?
1
撤销变量:
unset VARNAME
查看当前shell中变量:
set
查看当前shell中的环境变量:
printenv
env
export
#补上新变量
[root@localhost ~]# ANIMALS=pig
[root@localhost ~]# ANIMALS=$ANIMALS:goat
[root@localhost ~]# echo $ANIMALS
pig:goat
[root@localhost ~]# ANIMALS=$ANIMALS:sheep
[root@localhost ~]# echo $ANIMALS
pig:goat:sheep
变量不做算术运算:
[root@localhost ~]# A=2
[root@localhost ~]# B=3
[root@localhost ~]# C=$A+$B
[root@localhost ~]# echo $C
2+3
脚本:命令的堆砌,按实际需要,结合命令流程控制机制实现的源程序
Linux内核只能识别ELF格式
shebang:魔数
#!/bin/bash(解释器路径)
[root@localhost ~]# ls -l first.sh
-rw-r--r--. 1 root root 35 10月 16 08:56 first.sh
[root@localhost ~]# chmod +x first.sh
[root@localhost ~]# echo $PATH
/root/.nvm/versions/node/v10.7.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/git/bin:/root/bin
[root@localhost ~]# pwd
/root
[root@localhost ~]# ./first.sh
#
# /etc/fstab
# Created by anaconda on Mon Apr 2 20:22:35 2018
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/cl-root / xfs defaults 0 0
UUID=6f1b26d5-b889-4d35-b9d9-5c1b249e0557 /boot xfs defaults 0 0
/dev/mapper/cl-swap swap swap defaults 0 0
account cache db games kerberos local log nis preserve spool tmp
adm crash empty gopher lib lock mail opt run target yp
或者作为别的命令的参数执行:
[root@localhost ~]# bash first.sh
#
# /etc/fstab
# Created by anaconda on Mon Apr 2 20:22:35 2018
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/cl-root / xfs defaults 0 0
UUID=6f1b26d5-b889-4d35-b9d9-5c1b249e0557 /boot xfs defaults 0 0
/dev/mapper/cl-swap swap swap defaults 0 0
account cache db games kerberos local log nis preserve spool tmp
adm crash empty gopher lib lock mail opt run target yp
作为独立执行则必须给执行权限。
练习:写一个脚本,完成以下任务
1:添加5个用户,user1,…,user5
2:每个用户的密码同用户名,而且要求添加密码完成后不显示passwd命令的执行结果信息。
3:每个添加完成后,都要显示用户某某已经添加成功
useradd user1
echo "user1" | passwd --stdin user1 &> /dev/null
echo "Add user1 successfully"
条件判断:
如果用户不存在:
添加用户,给密码并显示添加成功。
否则
显示如果已经存在,没有添加
bash中如何实现条件判断?
条件测试类型:
整数测试
字符测试
文件测试
条件测试的表达式:
[ expression ]中括号两端必须有空格
[[ expression ]]
test expression
整数比较:
-eq:测试两个整数是否相等,比如$A -eq $B A和B中的值是否一样
-ne:测试两个整数是否不等:不等为真,相等为假
-gt:测试一个数是否大于另一个数,大于为真,否则为假
-lt:测试一个数是否小于另一个数,小于为真,否则为假
-ge:大于或等于
-le:小于或等于
命令的间逻辑关系:
逻辑与:&&
第一个条件为假时,第二条件不用再判断,最终结果已经有
第一个条件为真时,第二条件必须得判断。
[root@localhost ~]# id student2 &> /dev/null && echo "Hello,student2"
[root@localhost ~]# useradd student2
[root@localhost ~]# id student2 &> /dev/null && echo "Hello,student2"
Hello,student2
逻辑或:||
[root@localhost ~]# A=3
[root@localhost ~]# B=6
[root@localhost ~]# [ $A -eq $B ]
[root@localhost ~]# echo $?
1
如果用户user6不存在,就添加用户user6
! id user6 && useradd user6
id user6 || useradd user6
变量名称:只能包含字母、数字和下划线,并且不能数字开头;不应该跟系统中已有的环境变量重名。最好做到见名知义。
#second.sh
1 #!/bin/bash
2 LINES=`wc -l /etc/inittab`
3 echo $LINES
4 FINLINES=`echo $LINES | cut -d' ' -f1`
5 echo $FINLINES
[root@localhost ~]# ./second.sh
17 /etc/inittab
17
#判断是否为大文件
6 [ $FINLINES -gt 100 ] && echo "/etc/inittab is a big file"
#不是大文件则提示
[ $FINLINES -gt 100 ] && echo "/etc/inittab is a big file" || echo "/etc/inittab is a small file"
[root@localhost ~]# ./second.sh
17 /etc/inittab
17
/etc/inittab is a small file
如果用户存在,就显示用户已存在,否则就添加此用户:
id user1 && echo "user1 exists." || useradd user1
如果用户不存在,就添加;否则,显示其已经存在
! id user1 && useradd user1 || echo "user1 exists"
如果用户不存在,添加并且给密码;否则,显示其已经存在
! id user1 && useradd user1 && echo "user1" | passwd --stdin user1 || echo "user1 exists"
练习:写一个脚本,完成以下要求:
1.添加3个用户user1,user2,user3;但要先判断用户是否存在,不存在而后再添加;
2.添加完成后,显示一共添加了几个用户;当然,不能包括因为事先存在而没有添加的;
3.最后显示当前系统上共有多少个用户;
1 #!/bin/bash
2 ! id user1 &> /dev/null && useradd user1 && "user1" | passwd --stdin user1 &> /dev/n ull || echo "user1 exsits"
3 ! id user2 &> /dev/null && useradd user2 && "user2" | passwd --stdin user2 &> /dev/n ull || echo "user2 exsits"
4 ! id user3 &> /dev/null && useradd user3 && "user3" | passwd --stdin user3 &> /dev/n ull || echo "user3 exsits"
5 USERS=`wc -l /etc/passwd | cut -d: -f1`
6 echo "$USERS users"
[root@localhost ~]# ./addusers2.sh
./addusers2.sh:行2: user1: 未找到命令
user1 exsits
./addusers2.sh:行3: user2: 未找到命令
user2 exsits
user3 exsits
54 /etc/passwd users
[root@localhost ~]# ./addusers2.sh
user1 exsits
user2 exsits
user3 exsits
54 /etc/passwd users
判断是否为系统用户:
1 #!/bin/bash
2 NAME=user1
3 USERID=`id -u $NAME`
4 [ $USERID -eq 0 ] && echo "Admin" || echo "Common user."
[root@localhost ~]# chmod +x third.sh
[root@localhost ~]# ./third.sh
Common user.
条件判断,控制结构:
单分支if语句
if 判断条件;then
statement1
statement2
…
fi
双分支的if 语句:
if 判断语句;then
statement1
statement2
…
else
statement3
statement4
…
fi
1 #!/bin/bash
2 NAME=user1
3 if id=$NAME &> /dev/null; then
4 echo "$NAME exists"
5 fi
[root@localhost ~]# chmod +x usertest.sh
[root@localhost ~]# ./usertest.sh
user1 exists
练习:写一个脚本,完成以下任务
1.使用一个变量保存一个用户名
2.删除此变量中的用户,且一并删除其家目录
3显示“用户删除完成”类的信息
export USERNAME=username
userdel -r $USERNAME
echo $USERNAME"has been deleted"
1 #!/bin/bash
2 NAME=user1
3 if id=$NAME &> /dev/null; then
4 echo "$NAME exists"
5 else
6 useradd $NAME
7 echo $NAME | passwd --stdin $NAME &> /dev/null
8 echo "Add $NAME finished"
9 fi
练习:写一个脚本,完成以下要求:
给定一个用户:
1.如果其UID为0,就显示此为管理员
2.否则,就显示其为普通用户
1 #!/bin/bash
2 NAME=user16
3 USERID=`id -u $NAME`
4 if [ USERID -eq 0 ];then
5 echo "Admin"
6 else
7 echo "Common user"
或者
1 #!/bin/bash
2 NAME=user16
3 #引用执行结果而不是状态结果
4 if [ `id -u $NAME` -eq 0 ];then
5 echo "Admin"
6 else
7 echo "Common user"
8 fi
注意:“引用”一个命令的执行结果,要使用命令引用,比如:RESAULTS=`wc -l /etc/passwd | cut -d: -f1 `;
使用一个命令的执行状态结果,要直接执行此命令,一定不能引用,比如:if id user1 一句中的id命令就一定不能加引号
如果想把一个命令的执行结果赋值给某变量,要使用命令引用,比如USERID=`id -u user`
如果想把一个命令的执行状态结果保存下来,并作为命令执行成功与否的判断条件,则需要先执行此命令,而后引用其状态结果,如
id -u user1
RETVAL=$?
命令的引用
1 #!/bin/bash
2 grep "\<bash$" /etc/passwd &> /dev/null
3 RETVAL=$?
4 if [ $RETVAL -eq 0 ];then
5 USERS=`grep "\<bash$" /etc/passwd | wc -l`
6 echo "The shells of $USERS users are bash."
7 else
8 echo "No such user."
9 fi
#判断多少用户用bash shell
[root@localhost ~]# chmod +x bash.sh
[root@localhost ~]# ./bash.sh
The shells of 7 users are bash.
1 #!/bin/bash
2 grep "\<bash$" /etc/passwd &> /dev/null
3 RETVAL=$?
4 if [ $RETVAL -eq 0 ];then
#显示其中一个用户名
5 AUSER=`grep "\<bash$" /etc/passwd | head -1 | cut -d: -f1`
6 echo "$AUSER is one of such users"
7 else
8 echo "No such user."
9 fi
[root@localhost ~]# ./bash2.sh
root is one of such users
给定一个文件,判断是否有空白行?有则显示空白行数,否则,显示没有空白行
#/bin/bash
FILE=/etc/file1
if grep -n ^$ -nq 0;then
grep -n ^$ $FILE
else
echo "$FILE has no space"
给定一个用户,判断其UID和GID是否一样
如果一样,就显示此用户为“good guy”;否则显示为"bad guy"
#/bin/bash
USERNAME=user1
USERID=`id -u $USERNAME`
GROUPID=`id -g $USERNAME`
if [ $USERID -eq $GROUPID ]; then
echo "Good guy"
else
echo "Bad guy"
fi
不使用id命令获得其id号
echo $UID
给定一个用户,获取其密码警告期限
而后判断用户最近一次修改密码时间距今天是否已经小于警告期限;
提示:计算方法,最长使用期限减去已经使用的天数即为剩余使用期限;
最长使用时间是指从上回密码修改后还能使用多少天
[root@localhost ~]# TIMESTAMP=`date +%s`
[root@localhost ~]# let USEDAYS=$TIMESTAMP/86400
[root@localhost ~]# echo $USEDAYS
17820
判断命令历史中历史命令的总条目是否大于1000,如果大于,则显示"some command has been gone"
知识点:
bash命令中做算术运算:
1.let 算术运算表达式
[root@localhost ~]# A=3
[root@localhost ~]# B=6
[root@localhost ~]# let C=$A+$B
[root@localhost ~]# echo $C
9
2.$[ 算术运算表达式 ]
C=$[$A+$B]
[root@localhost ~]# D=$[$A+$B]
[root@localhost ~]# echo $D
9
3.$((算术运算表达式))
C=$(($A+$B))
4.expr 算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用
[root@localhost ~]# F=`expr $A + $B`
[root@localhost ~]# echo $F
9