Shell 脚本知识归纳

Shell脚本

(1)用途:
使用简单,是Shell命令的集合
运行节省时间
可实现批量管理,自动化
批量处理减少出错概率
(2)shell概述
shell:命令解释器,也是一个程序
种类:sh , bash ,ksh ,csh。。。

bash的特性:
a 历史记录 ----> 用户行为升级
b 别名 ----> 企业垃圾桶,rm --》mv
c 补全 ----> 命令($PATH),目录
d 支持通配符 ---->*[],[^]
e 前后台作业 ---->jobs, & ,bg,fg
f 运行脚本

系统shell类型

[root@nfs01 ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash

默认shell

[root@nfs01 ~]#  echo $SHELL
/bin/bash

bash安全性:

[root@nfs01 ~]# env x='(){:;}; echo be careful ' bash -c "echo this is a test"
this is a test

##如果返回 
be careful
this ia a test
则需要升级系统。

[root@nfs01 ~]# yum -y updata bash^C
[root@nfs01 ~]# rpm -qa bash
bash-4.2.46-31.el7.x86_64

(3)shell的建立
a 登录(交互)式Shell和非登录(交互)式Shell

登录式Shell:环境变量文件加载顺序 /etc/profile(/etc/profile.d/*),/.bash_profile,/.bashrc,/etc/bashrc
登录式shell场景:输入用户名和密码,“su - test002”

非登录式Shell:环境变量文件加载顺序 /.bash_profile,/.bashrc,/etc/bashrc ;
非登录式shell场景:“su test002”,定时计划任务,ansible的playbook。

b shell执行:加载环境变量ENV,该变量制定了环境文件(/etc/profile(/etc/profile.d/*),/.bash_profile,/.bashrc,/etc/bashrc) —》执行内容
(4)shell的执行
a 通过sh或者bash命令执行
b 直接运行,脚本必须要有可执行权限
c通过. 或者source 执行,在文件中的变量,函数的返回值将会加载到父及bash环境中。
d通过重定向,说明bash和sh是可以接受标准输入的
(6)shell脚本的注释
单行注释:#
多行注释::<<BLOCK
BLOCK
(7)shell脚本规范

shell变量
查看:env:  系统的全局变量
      set:  所有的全局变量
	  declare:  所有导入的全局变量和函数
	  
局部变量的定义
''  : 强引
""  :弱引
``  : 执行Shell命令	

(8)shell中常见的固定性的内容的生成
加密码:
Centos 6:
grub-md5-cryp

Centos 7:
grub2-mkpasswd-pbkdf2

grub-md5-crypt >> /etc/grub.conf
grub-md5-crypt |tee -a /etc/grub.conf

md5文件校验码:
[root@bogon test]# md5sum passwd1 
56cf56372303c1c769ec0d030144e60c  passwd1
[root@bogon test]# md5sum passwd
911bc5a50ff7cb7e2de6addb28c94abe  passwd

生成自然数:
方法一:
实例:

#!/bin/bash
read -p "请输入起始值:" sta
read -p "请输入终止值:" sto

for i in `eval echo {$sta..$sto}`
do
    echo $i
done
总结:bash不会解析多层变量,eval命令能解析多层变量。
[root@bogon test]# set 11 22 33 44
[root@bogon test]# echo $4
44
[root@bogon test]# echo $#   #打印参数的个数
4
[root@bogon test]# echo \$$#
$4
[root@bogon test]# eval echo \$$#
44

方法二

seq命令用于产生从某个数到另外一个数之间的所有整数。
seq [选项]... 尾数
seq [选项]... 首数 尾数
seq [选项]... 首数 增量 尾数
-f, --format=格式 使用printf 样式的浮点格式
-s, --separator=字符串 使用指定字符串分隔数字(默认使用:\n)
-w, --equal-width 在列前添加0 使得宽度相同
[root@nfs01 tmp]# seq -f "%3g" 8 12
  8
  9
 10
 11
 12
[root@nfs01 tmp]# seq -f "%03g" 8 12
008
009
010
011
012
[root@nfs01 tmp]# seq -w 8 12
08
09
10
11
12
[root@nfs01 tmp]# seq -s" " -f"str%02g" 9 11
str09 str10 str11
[root@nfs01 tmp]# seq -s"`echo -e "\t"`" 9 11
9       10      11
[root@nfs01 tmp]#  seq -s"`echo -e "\n"`" 9 11
19293949596979899910911
[root@nfs01 tmp]#  seq -s"=" 9 11
9=10=11

echo的参数等信息说明

echo参数选项 说明
-n 不换行输出内容
-e 解析转义字符
转义字符:
\n 换行
\r 回车
\t 制表符
\b 退格
\v 纵向制表符

生成随机数
方法一: $RANDOM
shell脚本----生成随机数

#!/bin/bash
function rand(){   
    min=$1  
    max=$(($2-$min+1)) 
    num=$(($RANDOM+1000000000)) #增加一个10位的数再求余   
    echo $(($num%$max+$min))  
    }   

read -p "please input your num of start:" sta
read -p "please input your num of end:" sto

rnd=$(rand $sta $sto)   
echo $rnd   
exit 0

方法二:openssl

[root@nfs01 ~]# openssl rand -base64 8 |md5sum  |cut -c 1-12
d2ddb347a589
[root@nfs01 ~]# openssl rand -base64 8 |cksum |cut -c 1-10     #最大十位
3441980797

生成UUID:

[root@nfs01 ~]# uuidgen
b9db1d55-411d-429f-86ab-39c1a7746abb
[root@nfs01 ~]# cat /proc/sys/kernel/random/uuid
ef2d4611-4bf8-4735-96f7-b8e7a342ff14

生成MAC:

[root@nfs01 ~]# echo "00:0c:29:`openssl rand -hex 3 | sed 's/\(..\)/\1:/g; s/.$//'`"
00:0c:29:48:7b:8f

(9)命令排序

;  拼接多个命令没有逻辑关系
[root@bogon test]# ll 123;sh useradd.sh 
&& 拼接多个命令,有逻辑关系
[root@bogon test]# sh useradd.sh && ll 123
[root@bogon test]# ll 123 && sh useradd.sh
|| 拼接命令,有逻辑关系,
[root@bogon test]# ll 123 || sh useradd.sh

注意:
command & 后台执行
command &>/dev/null 混合重定向(标准输出1,错误输出2
command1 && command2 命令排序,逻辑判断

(10)位置变量:
$0,
$1,$2 … 9 , 9, {10},${11} … # 接收脚本或者函数的位置参数。
$0 文件名,若执行脚本时带有路径,会将路径和将本名同事输出。
$# 表示参数的个数

Shell进程的特殊状态变量说明
$?:获取执行上一个指令的执行状态返回值
$$:获取当前执行的shell脚本的进程号(PID)
$!:获取上一个在后台工作的进程的进程号
$_:获取在此之前执行的命令或脚本的最后一个参数

在企业场景下,"$?"返回值的用法如下:
1)判断命令,脚本或函数等程序是否执行成功
2)若在脚本中调用执行"exit数字",则会返回这个数字给"$?"变量
3)如果是在函数里,则通过"return 数字"把这个数字一函数返回值的形式传给"$?"

(11)dirname,basename

[root@bogon test]# dirname /root/test/var2.sh 
/root/test
[root@bogon test]# basename /root/test/var2.sh 
var2.sh

实例:

#!/bin/bash
echo $0
echo "`dirname $0`"   #dirname 打印路径
echo "`basename $0`"  #basename 打印文件名

(12)状态变量

1)判断上一条命令是否执行成功,成功则返回0,不成功则返回非0
2)获取脚本的exit的退出码
3)获取的是函数的返回值

实例:监控web服务状态是否正常
思路
a 判断进程:[root@bogon test]# ps -ef |grep httpd
[root@bogon test]# killall -0 httpd
b 判断端口:[root@bogon test]# netstat -tunalp |grep 80
c判断链接:[root@bogon test]# curl 127.0.0.1

[root@bogon test]# cat monitor_httpd.sh 
#!/bin/bash
service=httpd
while true
do
killall -0 $service &>/dev/null
#curl 127.0.0.1  &>/dev/null
#`ps -ef |grep httpd |grep -v grep` &>/dev/null
#`netstat -tulanp |grep 80` &>/dev/null
if [ $? -eq 0 ]
then
    echo "httpd is up ..."
else
    echo "httpd is down ..."
fi
sleep 1
done

EXEC
功能:exec命令能够在不创建新的子进程的前提下,转去执行指定的命令,当指定的命令执行完毕后,该进程(也就是最初的shell)就终止了
(14)常见的内置命令
a : echo
-e :解析转义字符
-n :不换行输出

rnd=$(rand $1 $2)
echo -ne "随机数是: \t$rnd"   
echo -e "\t请拿好..."
exit 50

b: exec :在不启动子进程的前题下运行命令,执行完后杀死当前进程。
c: read -p :读取用户输入的内容
d: shift :移动位置参数
实例:企业垃圾桶参数偏移

[root@bogon test]# cat rm.sh 
#!/bin/bash
[ -d /dev/mynull ] || mkdir /dev/mynull
shift
mv $1 /dev/mynull

e: exit n (数字)
$?
(13)字符串操作

定义:
[root@bogon test]#a=daahufsuufsdghfgdiha
[root@bogon test]#a="cnsjv dsjf dshs"
[root@bogon test]#a='afnkjs$a##w*l'

查看:
[root@bogon test]# echo $a
[root@bogon test]# echo ${a}
afhkjsfjsdfjdskfasli$alkdahkjf

获取字符串长度: 
[root@bogon test]# echo ${#a}

截取子串:
[root@bogon test]# echo ${a:4}   #从第5个位置开始取子串
[root@bogon test]# echo ${a:4:1}   #从第5个位置开始取1个字符
[root@bogon test]# echo ${a#w*l}  #从左向右最短匹配
[root@bogon test]# echo ${a##w*l}  #从左向右最长匹配 
[root@bogon test]# echo ${a%l*x}    #从右往左最短匹配
[root@bogon test]# echo ${a%%l*x}    #从右往左最长匹配

[root@bogon test]# echo ${a/l*x/00000}  #最大范围匹配到的字符替换
[root@bogon test]# echo ${a/l/0}    #从左向右替换第一个匹配到的字符 
[root@bogon test]# echo ${a//l/0}   #从从往右替换所有匹配到的字符 
[root@bogon test]# cat file3.sh 
#!/bin/bash
#"如何修改shell中的for循环,使其不以空格分割。而是以换行"
#IFS:
IFS_old=$IFS
IFS=$'\n'
for i in `ip a |grep -E '\<inet\>'` #for 循环默认以空格分割,---""
do
    #echo $IFS
    #echo $i
    j=${i#*t}
    echo ${j%%/*}
    #echo ${j%%s*o}
done
IFS=$IFS_old

(14)字符串的特殊变量扩展

echo ${parameter:-word} :如果parameter为空,则输出word,parameter本身没有发生变化;如果不为空输出parameter的值。
echo ${parameter:=word} :如果parameter为空,则输出word,parameter已经赋予word的值;如果不为空输出parameter的值。
echo ${parameter:?word} :如果parameter为空,则输出word,此时word将是错误输出的提示,echo $? 返回值为1;如果不为空输出parameter的值。
echo ${parameter:+word} :如果parameter为空,则输出空,如果不为空输出word,parameter本身没有发生变化。

定时计划任务坑:

1[root@server02 ~]# vim /var/spool/cron/root 这样做,权限不对,正确的方法是crontab -e;.vimrc.bak;	
     -rw------- 1 root root 9 6  23 18:35 root	
2:计划任务在执行时,是在自己的家目录下执行的,所以脚本中一定要写绝对路径。
[root@bogon test]# crontab -e

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
#
0 */1 * * * . /etc/profile;/root/test/ping_log.sh
#c
0 0 */1 * * . /etc/profile;/root/test/ping_log1.sh

(17)shell中的数值计算
a: (()) :既能做数值运算,又能做数值比较

[root@bogon test]# a=$((1+1))
[root@bogon test]# echo a
a
[root@bogon test]# echo $a
2

if ((1>2))
then
    echo "ok"
else
    echo "not ok"
fi

b: let :数值运算

[root@bogon test]# let a=1+2
[root@bogon test]# echo $a
3

c: expr :数值运算(判断是否为数字),字符串对比(判断两字符串是否一致),求字串长度

[root@bogon test]# expr 1 + 2
3  
[root@bogon test]# expr 1 \* 2
2
[root@bogon test]# expr 1 \/ 2
0
[root@bogon test]# expr 1 \% 2
1


字符串匹配。匹配的字符串以“:”相隔,匹配则为真,反之,为假。
[root@bogon test]# expr "123" : "124" &>/dev/null
[root@bogon test]# echo $?
1
[root@bogon test]# expr "123" : "123" &>/dev/null
[root@bogon test]# echo $?
0

猜你喜欢

转载自blog.csdn.net/weixin_45961525/article/details/107199536