Linux 学习之路(五):bash脚本编写

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

猜你喜欢

转载自blog.csdn.net/nicezheng_1995/article/details/83088617