马哥07-shell脚本编程基础

文章目录

  • SHELL脚本编程基础
    • 创建脚本
    • 脚本调试
  • 变量
    • 变量赋值及引用
  • 变量类型
    • 局部变量
    • 环境变量
    • 本地变量
    • 位置变量
    • 特殊变量
    • 只读变量
  • 算数运算
    • 实现算术运算
    • 生成随机数
  • SHELL脚本逻辑判断
    • 条件测试
    • bash的字符串测试
    • 文件测试
  • read接受输入
  • 条件语句
  • 课后练习

SHELL脚本编程基础

创建脚本

因为shebang机构,所以shell脚本格式要求如下:首先vim HELLO.sh

#!/bin/bash
#
#echo "hello word"

bash执行

[root@localhost ~]#
bash HELLO.sh
hello word

新建PATH文件路径

[root@localhost ~]#
vim /etc/profile.d/newfile.sh
[root@localhost ~]#vim 新的文件.sh
#在新文件.sh文件里编辑:PATH=/data/新的目录/:$PATH
#记得chmod +x 文件名.sh,加权限噢

脚本调试

语法检查
bash -n filename.sh
调试执行
bash -x filename.sh

变量

作用
1.数据存储方式
2.参与的运算
3.表示的数据范围

shell中变量命名法则
1.不能以程序中的保留字.例如:if.for
2.只能使用数字、字母及下划线、且不能以数字开头
3.见名知意
4.统一命名规则:驼峰命名法即f分大驼峰:FileName;小驼峰:fileName
shell中命名建议规则
1.变量名大写
2.局部变量小写
3.函数名小写
4.用英文名,并体现出实际作用

变量赋值及引用

赋值
可直接是字符串:
1.name=sunxiaobo
2.name=“sunxiaobo”

变量的引用:
name="$PATHNAME"

命令的引用:
1.name=COMMAND
2.name=$((COMMAND))

引用
1.echo $name
2.echo ${name}

#set可以显示已定义的所有变量
#unset PATHNAME可用于删除变量的值(常用于脚本最后)

[root@localhost ~]#unset name
[root@localhost ~]#echo $name

[root@localhost ~]#

强弱引用
""弱引用,其中的变量引用会被替换为变量值
''强引用,其中的变量引用不会被替换为变量值而保持原字符串

相关小命令
echo $BASHPID #查看对应进程编号
echo $PPID #查看父进程编号

变量类型

局部变量

1.当前shell生效
2.无法被子进程继承

环境变量

1.定义环境变量:
ecport name=PATHNAME
declare -x name=PATHNAME
2.查看所有环境变量:export、env、pritenv、declare -x

本地变量

函数中的变量

位置变量

变量 用途
$NUM 第NUM个参数
$0 命令本身
$* 传递给脚本的所有参数,所有参数合一字符串
$@ 传递给脚本的所有参数,每个参数为独立字符串
$# 传递给脚本的参数的个数
$? 执行成功与否(0成功)(1-255失败)

注意: @ 、 @、 @*只在被双引号包起来的时候才会有差异

特殊变量

只读变量

readonly又称常量
面试题:

[root@localhost ~]#TITLE=ceo
[root@localhost ~]#echo $TITLE
ceo
[root@localhost ~]#(echo $TITLE;TITLE=COO;echo $TITLE)
ceo
coo
[root@localhost ~]#echo $TITLE
ceo

注意:
{}不开启子进程
()开启子进程
#内置命令和变量赋值只影响小括号里的变量环境,不影响小括号外面的变量环境。

算数运算

实现算术运算

+、-、*、%(取模、取余)、**(乘方)

#乘除符号有些场景需要转义    
1.let var =算术运算   
2.var = $[ 算术运算 ]  
3.var = $(( 算术运算 ))  
4.var = $(expr NUM1 NUM2)  
5.declare -i var = 数值 
6.echo " 算术运算 " | bc  

生成随机数

$RANDOM
例如:echo [ [ [RANDOM%50]

SHELL脚本逻辑判断

条件测试

1.条件测试语法

-eq 相等
-ne 不相等
-lt 小于
-le 小于等于
-gt 大于
-ge 大于等于

真true:0
假false:1

2.测试命令
test 表达式

[ “表达式” ]

[[ “表达式” ]]

短路真/短路假
CMD1 && CMD2 || CMD3
CMD1结果返还true执行CMD2;CMD1结果返还false执行CMD3.

bash的字符串测试

字符 用途
= 是否等于
> 是否大于(ascii码))
< 是否小于
!= 是否不等
== 使用通配符与右边匹配
=~ 使用正则表达式与右边匹配,一般用于[[]]中
-z “STRING” 字符串是否为空,空为真,不空为假
-n “STRING” 字符串是否不为空,空为假,不空为真

文件测试

文件类型存在测试

语法 用途
-a FILE 同-e
-e FILE 文件是否存在
-b FILE 文件是否存在(块设备文件)
-c FILE 文件是否存在(字符文件)
-d FILE 目录是否存在
-f FILE 文件是否存在(普通文件)
-h FILE 或 -L FILE 是否纹在符号链接文件
-p FILE 是否存在管道文件
-S FILE 是否存在套接字文件

文件权限测试

语法 用途
-r FILE 可读
-w FILE 可写
-x FILE 可执行
-u FILE 是否suid权限
-g FILE 是否sgid权限
-k FILE 是否sticky权限

文件属性测试

语法 用途
FILE1 -ef FILE2 FILE是否为FILE2的硬链接
FILE1 -nt FILE2 FILE是否新于FILE2(mtime)
FIEL1 -ot FILE2 FILE是否旧于FILE2

bash的组合测试条件
第一种方式:
COMMAND1 && COMMAND2 并且
COMMAND1 || COMMAND2 或者
!COMMAND 非
第二种方式:
COMMAND1 -a COMMAND2 并且;短路与
COMMAND1 -o COMMAND2 或者;短路或
!COMMAND 非

read接受输入

read [OPTION] VAR…

#使用read来把输入值分配给一个或多个变量
-p STRING   #指定要显示的提示    
-s          #静默输入,一般用于密码   
-n NUM      #指定输入的字符长度NUM  
-d CHAR     #指定结束符CHAR  
-t NUM      #指定时间为NUM 
#read 从标准输入中读取值,给每个单词分配一个变量,所剩词条多被分配给最一个变量

一次对多个变量赋值

[root@localhost ~]#read A B C <<< "aa bb cc"
[root@localhost ~]#echo $A
aa
[root@localhost ~]#echo $B
bb
[root@localhost ~]#echo $C
cc

从管道获得值

[root@localhost ~]#echo sun | { read NAME;echo $NAME; }
sun

条件语句

if语句

单分支:

if CONDITION(判断条件); then
	CODE(条件为真的分支代码)
else
	CODE(条件为假的分支代码)
fi
嵌套式:

if CONDITION(判断条件1);then
	CODE(条件1为真的分支代码)
elif CONDITION(判断条件2);then
	CODE(条件2为真的分支代码)
else
	CODE(条件2为假的分支代码)
fi

case语句

case $VAR(变量引用) in
PAT1)
	CODE(满足条件1的分支代码)
	;;
PAT2)
	CODE(满足条件2的分支代码)
	;;
*)
	CODE(都不满足条件的分支代码)
	;;
esac

case语句支持的glob风格的通配符
*: 任意长度字符
?: 任意单个字符
[]: 指定范围内的任意单个字符
a|b: a或b

bash如何展开命令
把命令行分成单个命令词
展开别名
展开大括号的申明({})
展开波浪符声明(~)
命令替换$() 和``)
再次把命令行分成命令词
展开文件通配(*、?、[abc]等等) 准备I/O重导向(<>)
运行程序
防止扩展

反斜线()会使随后的字符按原意解释    
$echo Your cost:\$5.00    
Your cost:$5.00    
加引号来防止扩展    
单引号(')防止所有扩展    
双引号(")也防止所有扩展,但是以下情况例外:   
$(美元符号)   -  变量扩展  
`(反引号)     -  命令替换  
\(反斜线)     -  禁止单个字符扩展
括号的申明({})  
展开波浪符声明(~)  
命令替换$() 和``)  
再次把命令行分成命令词  
展开文件通配(*、?、[abc]等等)  准备I/O重导向(<>)  
运行程序  

防止扩展

反斜线(\)会使随后的字符按原意解释  
$echo Your cost:\$5.00  
Your cost:$5.00  
加引号来防止扩展  
单引号(')防止所有扩展  
双引号(")也防止所有扩展,但是以下情况例外:  
$(美元符号)   -  变量扩展    
`(反引号)     -  命令替换  
\(反斜线)     -  禁止单个字符扩展
!(叹号)       -  历史命令扩展

课后练习

编写脚本 systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小。

#!/bin/bash
IPV4=`ifconfig|grep -Eo "\b([1-9]|[1-9][0-9]|1[0-9]{2}|2[01][0-9]|22[0-3])\b(\.\b([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b){2}\.\b([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b"`

echo "当前主机系统信息如下:"
echo 主机名:`hostname`
echo ipv4地址:"$IPV4"
echo 操作系统版本:`cat /etc/redhat-release|cut -d. -f1-2`
echo 内核版本:`uname -r`
echo CPU型号:`lscpu|grep "Model name"|tail -1|tr -s ' '|cut -d: -f2`
echo 内存大小:`free -mh|head -2|tail -1|tr -s ' '|cut -d' ' -f2`
echo 硬盘容量:`fdisk -l|head -2|tail -1|cut -d, -f1|cut -d' ' -f2-4`

编写脚本 backup.sh,可实现每日将/etc/目录备份到/backup/etcYYYY-mm-dd中。

#!/bin/bash
cp -a /etc/ /data/etc`date +%Y-%m-%d` &> /dev/null
echo "/etc目录备份完成

编写脚本 disk.sh,显示当前硬盘分区中空间利用率最大的值。

#!/bin/bash
echo "当前硬盘分区中空间利用率最大值:`df|grep /dev/sd|grep -o "[0-9]\{1,3\}%"|sort -nr|head -1`"

编写脚本 links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序。

#!/bin/bash
echo "每个远程主机的IPV4地址和连接数:`netstat -tan|tr -s " " ":"|cut -d: -f6|grep ^[[:digit:]]|sort|uniq -c|sort -nr`"

编写脚本 sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和。

#!/bin/bash
space1=`cat $1|grep "^$"|wc -l`
space2=`cat $2|grep "^$"|wc -l`
let sum=space1+space2

编写脚本 sumfile.sh,统计/etc, /var, /usr 目录中共有多少个一级子目录和文件。

#!/bin/bash
numetc=`ls -A /etc|wc -l`
nuvar=`ls -A /var|wc -l`
numusr=`ls -A /usr|wc -l`
let sum=numetc+numvar+numusr
echo $sum

编写脚本 argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数。

#!/bin/bash
[[ $# -lt 1  ]] && ( echo "at least one argument" && exit ) || echo `grep "^$" $1|wc -l`

编写脚本 hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”。

#!/bin/bash
ping -c1 -w1 $1 &> /dev/null && echo "$1 is up"||echo "$1 is down"

编写脚本 checkdisk.sh,检查磁盘分区空间和inode使用率,如果超过80%,就发广播警告空间将满。

#!/bin/bash
disk=`df|egrep /dev/sd|tr -s ' ' '%'|cut -d% -f5|sort -nr|head -n1`
inode=`df -i|egrep /dev/sd|tr -s ' ' '%'|cut -d% -f5|sort -nr|head -n1`
[ $disk -ge 80 -o $inode -ge 80 ] && echo wall space will full

编写脚本 per.sh,判断当前用户对指定参数文件,是否不可读并且不可写。

#!/bin/bash
[ ! -r "$1" -a ! -w "$1"  ] && echo "$1 is not read an write" || exit
#注意:执行时请以一般用户执行,以root执行无法显示结果

编写脚本 excute.sh ,判断参数文件是否为sh后缀的普通文件,如果是,添加所有人可执行权限,否则提示用户非脚本文件。

#!/bin/bash
[[ $1 =~ .sh$  ]] && (chmod a+x $1;echo "$1 is .sh")||echo "$1 is not .sh"

编写脚本 nologin.sh和 login.sh,实现禁止和允许普通用户登录系统。

#!/bin/bash
[ -f  /etc/nologin ]&& echo "nologin"||(touch /etc/nologin;echo "nologin")
#!/bin/bash
[ -f /etc/nologin  ]&& (rm -f /etc/nologin;echo "login")||echo "login"

编写脚本 createuser.sh,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息。

#!/bin/bash
read -p "please input username:" user
id $user &>/dev/null
[[ ! $? -eq 0  ]]&&(useradd $user&> /dev/null && echo "add $user user") ||echo "the user is exit"

编写脚本 yesorno.sh,提示用户输入yes或no,并判断用户输入的是yes还是no,或是其它信息。

#!/bin/bash
read -p "Do you agree?(yes or no):" ANS
[[ "$ANS" =~ ^[Yy][Ee][Ss]|[Yy]$ ]] && { echo OK ; exit ; }
[[ "$ANS" =~ ^[Nn][Oo]|[Nn]$  ]] && { echo Not OK ; exit ; }
echo "Your input is false"

编写脚本 filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类型)

#!/bin/bash
read -p "please input file path: " path
a=`ls -l $path|grep -o "^."`
	case $a in
	-)
	echo "common file"
;;
	d)
	echo "directory file"
;;
	1)
	echo "linked file"
;;
	*)
	echo "other file"
;;
	esac

if [ -z "$1" ];then
	echo there must be a filename argument
	exit 1
elif	[ ! -e "$1" ]; then
	echo no such file
	exit 1
elif	[ -d "$1"  ]; then
	echo directory file
	exit 0
elif	[ -L "$1"  ]; then
	echo link file
	exit 0
elif	[ -f "$1"  ]; then
	echo normal file
	exit 0
else
	echo other file
	exit 0
fi

编写脚本 checkint.sh,判断用户输入的参数是否为正整数。

#!/bin/bash
read -p "please input a number:" NUM
[[ $NUM =~ ^[0-9]+$ ]] && echo $NUM is int ||{ echo "please input a number"; exit ; }

你可能感兴趣的:(马哥07-shell脚本编程基础)