shell的脚本的基本用法-

目录

使用read命令来接受输入

if语句

条件判断 case 语句         就是判断对错是否成立

case支持glob风格的通配符:

循环while 

循环 until

循环 for

循环中本轮退出循环continue

提前结束第N层整个循环 break

循环逐个参数处理 shift

防止Dos攻击的脚本

fork 炸弹

循环与菜单 selec

函数介绍

 语法

 查看函数

 删除函数

范例

 在脚本中定义及使用函数

函数变量

函数返回值

信号捕捉 trap 修改信号原来的功能,实现自定义功能 

当脚本正常或异常退出时,也会执行finish函数 

创建临时文件 mktemp

安装复制文件 install

交互式转化批处理工具 expect 

非交互式复制文件    不是shell不能用bash

expect 变量

expect 位置参数 

shell脚本调用 expect

shell脚本利用循环调用expect在CentOS和Ubuntu上批量创建用户

数组

删除数组

基于模式取子串


使用read命令来接受输入

每个管道符的输出都是运行在独立的子进程中  

[root@CentOS ~]# echo 1 3 | read a c ; echo a=$a c=$c 
a= c= 
[root@CentOS ~]# echo 1 3 | { read a c;echo $a $c; }
1 3
[root@CentOS ~]# echo 1 3 |(read a c;echo $a $c)
1 3

使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量。需要精确把控

-p         指定要显示的提示
-s         静默输入,一般用于密码
-n         N 指定输入的字符长度N
-d         '字符' 输入结束符
-t         N TIMEOUT为N秒

[root@CentOS ~]# read name wang wei
123 456 789
[root@CentOS ~]# echo $wei
789
[root@CentOS ~]# echo $wang
456
[root@CentOS ~]# echo $name
123
if语句

单分支  

if 判断条件;     then

      条件为真的分支代码

fi

双分支

if 判断条件;   then

      条件为真的分支代码        

else

          条件为假的分支代码   

fi

多分支

if 判断条件1; then
     条件1为真的分支代码
elif 判断条件2; then
      条件2为真的分支代码
elif 判断条件3; then
      条件3为真的分支代码
...
else
以上条件都为假的分支代码
fi

条件判断 case 语句         就是判断对错是否成立

#!/bin/bash
read -p "please input a word ,and user enter to check:" KEY
		#输入关键词
case "$KEY" in
[a-z]|[A-Z])		#判断他的格式为字符
        echo "what you input is word";;
[0-9])		#判断他的格式为数字
        echo "what you input is number";;
*)		#判断他的格式为符号
        echo "what you input is symbol";;
esac

case支持glob风格的通配符:

* 任意长度任意字符
? 任意单个字符
[] 指定范围内的任意单个字符
| 或者,如: a|b

 循环while 

这种循环就很简单直白了,如果循环表达式为真就执行循环体, 每次执行循环体前都要先判断下,知道循环表达式为假就结束循环。

   true  (敲他永远为真)     filse(敲他永远为假)

int n=10; 
while(n>0)
{
    printf("看到这里的小可爱最帅/最美\n");
    n--;
} 


报警通知
dd if=/dev/zero of=/boot/f1.img bs=1M count=700

#!/bin/bash
WAPNING=80
while :;do
    USE=`df |sed -rn '/^\/dev\/sd/s#.* ([0-9]+)%.*#\1#p' |sort -nr|head -n1`
    if [ $USE -gt $WAPNING ];then
        echo DISk will de full from `hostname -I` | mail -s "disk warning" 704318431@qq.com
    fi
    sleep 10
done

 循环 until

正确true退出, 错误false循环

until COMMANDS; do COMMANDS; done
until CONDITION; do
        循环体
done

无限循环

until false; do
循环体
Done

循环 for

使用glob,如:*.sh

变量引用,如:$@,$*,$#    # 

  •  $@是整体  全部参数合为一个字符串
  • $*是单个 每个参数是单独字符串
  • $# 传递给脚本的参数个数

同理位置参数它可以代表多个参数

[root@CentOS shell]# bash for.sq 2 3 5
sum=10
[root@CentOS shell]# cat for.sq 
#!/bin/bash
sum=0
for i in $@; do
    let sum+=i
done
echo sum=$sum

for NAME [in WORDS ... ] ; do COMMANDS; done
#方式1
for 变量名  in 列表;do
 循环体
done
#方式2
for 变量名  in 列表
do
 循环体
done

[root@CentOS wang]# for i in $(seq 10);do echo i=$i;done
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
i=10
[root@CentOS wang]# for i in `seq 10`;do echo i=$i;done  和上面一个意思

[root@CentOS wang]# sum=0;for i in {1..100};do let sum+=i;done;echo sum=$sum
sum=5050
[root@CentOS wang]# seq -s+ 100|bc
5050
9*9乘法表

for i in {1..9};do
    for j in `seq $i`;do
        echo -e "${j}x${i}=$[j*i]\t\c"
  done
  echo
done

-e 是用于启用 echo 命令的转义字符解释功能的选项
\t 是转义字符,表示制表符,用于在乘法表达式和结果之间创建一些间距。
\c 是另一个转义字符,用于告诉 echo 命令在输出行的末尾不要添加换行符(即不换行),这样可以在同一行上打印多个乘法表达式和结果。
echo:这个命令在每次内部循环完成后输出一个换行符,以开始新的行。

倒叙的

for i in {1..9};do

   for j in $(seq `echo $[10-$i]`);do

       echo -ne "${j}x`echo $[10-i]`=$(((10-i)*j))\t"

   done

   echo

done

检测正在运行的主机

[root@CentOS shell]# cat for_scan_host.sh
#!/bin/bash
NET=10.0.0
for ID in {1..254};do
{
ping -c1 -W1 NET.NET.ID &> /dev/nbll && echo NET.NET.ID is up || echo NET.NET.ID is down
}&
done
wait

打印三角形

#!/bin/bash
read -p "请输入三角形的行数" line
for ((i=1;i<=$line;i++));do
    for ((k=0;k<=$line-i;k++));do
        echo -e ' \c'
    done
    for((j=1;j<=2*i-1;j++));do
        echo -e '*\c'
    done
    echo
done

          *
         ***
        *****
       *******
      *********
     ***********
    *************
   ***************
  *****************
 *******************

循环中本轮退出循环continue

[root@CentOS shell]# vim aa.sh
[root@CentOS shell]# cat aa.sh 
for ((i=0;i<10;i++));do
    for((j=0;j<10;j++));do
        [ $j -eq 5 ] && continue 
        echo $j
    done
    echo ---------------------------
done

---------------------------
0
1
2
3
4
6
7
8
9
---------------------------、

[root@CentOS shell]# cat aa.sh 
for ((i=0;i<10;i++));do
    for((j=0;j<10;j++));do
        [ $j -eq 5 ] && continue 2       2就是跳过外层循环  所以才0-4
        echo $j
    done
    echo ---------------------------
done
[root@CentOS shell]# bash aa.sh 
0
1
2
3
4
0
1
2
3
4

提前结束第N层整个循环 break

最内层为第1层 

[root@CentOS shell]# cat aa.sh 
for ((i=0;i<10;i++));do
    for((j=0;j<10;j++));do
        [ $j -eq 5 ] && break        #break是结束当前整轮循环,所以是0-4,这是循环套循环,里面的循环结束就执行外面的循环所以才有------
        echo $j
    done
    echo ---------------------------
done
aa.sh
0
1
2
3
4
---------------------------
0
1
2
3
4
---------------------------

循环逐个参数处理 shift

shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到 shift 

PASS=123456
while [ "$1" ];do
    useradd $1 && echo $1 is created || echo $1 is exist
    echo $PASS | passwd --stdin $1  &> /dev/null
    shift
done
                                                                             
[root@CentOS wang]# bash user.sh dd gg bb
dd is created
更改用户 dd 的密码 。
passwd:所有的身份验证令牌已经成功更新。
gg is created
更改用户 gg 的密码 。
passwd:所有的身份验证令牌已经成功更新。
useradd:用户“bb”已存在
bb is exist
更改用户 bb 的密码 。
passwd:所有的身份验证令牌已经成功更新。

[root@CentOS wang]# tail /etc/passwd
wei:x:1003:1003::/home/wei:/bin/bash
ss:x:1004:1004::/home/ss:/bin/bash
xx:x:1005:1005::/home/xx:/bin/bash

防止Dos攻击的脚本

WARNING=10
touch deny_hosts.txt
while true;do
   ss -nt | sed  -nr '1!s#.* ([0-9.]+):[0-9]+ *#\1#p'|sort |uniq -c|sort | 
while read count ip;do 
        if [ $count -gt $WARNING ];then
            echo $ip is deny 
            grep -q "$ip" deny_hosts.txt || { echo $ip >> deny_hosts.txt; 
iptables -A INPUT -s $ip -j REJECT; } 
        fi
    done
    sleep 10
done

fork 炸弹

是一种恶意程序,它的内部是一个不断在 fork 进程的无限循环,实质是一个简单的递归程序。由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源
参考:https://en.wikipedia.org/wiki/Fork_bomb
一个意思

:(){ :|:& };:
bomb() { bomb | bomb & }; bomb    

循环与菜单 selec

  • select 循环主要用于创建菜单,按数字顺序排列的菜单项显示在标准输出上
  • 用户输入菜单列表中的某个数字,会将对应的WORD值赋值给NAME变量
  • 用户输入被保存在内置变量 REPLY 中  
  • PS3显示提示信息
[root@CentOS ~]# select MENU in 北京烤鸭 佛跳墙 小龙虾 羊蝎子 火锅 点菜结束;do echo  $MENU;done
1) 北京烤鸭
2) 佛跳墙
3) 小龙虾
4) 羊蝎子
5) 火锅
6) 点菜结束
#? 2
佛跳墙
cat select.sh
#!/bin/bash
#
sum=0
PS3="请点菜(1-6): "
select MENU in 北京烤鸭 佛跳墙 小龙虾 羊蝎子 火锅 点菜结束;do
case $REPLY in
1)
echo $MENU 价格是 100
let sum+=100
;;
2)
echo $MENU 价格是 88
let sum+=88
;;
3)
echo $MENU价格是 66
let sum+=66
;;
4)
echo $MENU 价格是 166
let sum+=166
;;
5)
echo $MENU 价格是 200
let sum+=200
;;
6)
echo "点菜结束,退出"
break
;;
*)
echo "点菜错误,重新选择"
;;
esac
done
echo "总价格是: $sum"

[root@CentOS wang]# bash select.sh 
1) 北京烤鸭
2) 佛跳墙
3) 小龙虾
4) 羊蝎子
5) 火锅
6) 点菜结束
请点菜(1-6): 2
佛跳墙 价格是 88
请点菜(1-6): 3
小龙虾价格是 66
请点菜(1-6): 1
北京烤鸭 价格是 100
请点菜(1-6): 6
点菜结束,退出
总价格是: 254

函数介绍

  • 函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程
  • 它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分

 语法

#语法一:
func_name (){
...函数体...
}
#语法二:
function func_name {
...函数体...
}
#语法三:
function func_name () {
...函数体...
}

 查看函数

#查看当前已定义的函数名
declare -F
#查看当前已定义的函数定义
declare -f
#查看指定当前已定义的函数名
declare -f func_name
#查看当前已定义的函数名定义
declare -F func_name
类拟于环境变量,也可以定义环境函数,使子进程也可使用父进程定义的函数
export -f function_name
declare -xf function_name
查看环境函数:
export -f
declare -xf

 删除函数

unset func_name

范例

:实现判断CentOS的主版本

[root@centos8 ~]#centos_version() {
> sed -rn 's#^.* +([0-9]+)\..*#\1#p' /etc/redhat-release
> }
[root@centos8 ~]#centos_version
8

 在脚本中定义及使用函数

disable_selinux(){
    sed -i.bak 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
    echo "SElinux已禁用,重新启动后才可生效"
}
    disable_firewall(){
        systemctl disable --now firewalld &> /dev/null
        echo "防火墙已禁用"
}
set_ps1() {
    echo "PS1='\[\e[1;35m\][\u@\h \W]\\$\[\e[0m\]'" > /etc/profile.d/reset.sh
    echo "提示符已修改成功,请重新登录生效"
}
set_eth(){
    sed -i.bak '/GRUB_CMDLINE_LINUX=/s#"$# net.ifnames=0"#' /etc/default/grub
    grub2-mkconfig -o /boot/grub2/grub.cfg &> /dev/null
    echo "网络名称已修改成功,请重新启动才能生效"
}
PS3="请选择相应的编号(1-6): "
MENU='
禁用SELinux
关防火墙
修改提示符
修改网卡名
以上全实现
退出
'
select M in $MENU ;do
case $REPLY in
1)
    disable_selinux
    ;;
2)
    disable_firewall
    ;;
3)
    set_ps1
    ;;
4)
    set_eth
    ;;
5)
    disable_selinux
    disable_firewall
    set_ps1
    set_eth
    ;;
6)
    break
    ;;
*)
    echo "请输入正确的数字"
esac
done

[root@CentOS wang]# bash hanshu.sh 
1) 禁用SELinux	3) 修改提示符	5) 以上全实现
2) 关防火墙	4) 修改网卡名	6) 退出
请选择相应的编号(1-6): 1
SElinux已禁用,重新启动后才可生效
请选择相应的编号(1-6): 2
防火墙已禁用
请选择相应的编号(1-6): 3
提示符已修改成功,请重新登录生效
请选择相应的编号(1-6): 4
网络名称已修改成功,请重新启动才能生效
请选择相应的编号(1-6): 6

函数变量

在函数中定义本地变量的方法

注意:

  • 如果函数中定义了普通变量,且名称和局部变量相同,则使用本地变量
  • 由于普通变量和局部变量会冲突,建议在函数中只使用本地变量

local NAME=VALUE  在当前进程有效。子进程无效

显示成功和失败的颜色   sentos有   ubuntu没有

[root@CentOS ~]#cd  /etc/init.d/
[root@CentOS init.d]#. functions 
[root@CentOS init.d]#action "rm -rf /data"
rm -rf /data                                               [  确定  ]
[root@CentOS init.d]#action "rm -rf /data" false
rm -rf /data                                               [失败]
函数返回值

使用exit退出的是函数和脚本,使用return退出的是函数return只能用函数

信号捕捉 trap 修改信号原来的功能,实现自定义功能 

#进程收到系统发出的指定信号后,将执行自定义指令,而不会执行原操作
trap '触发指令' 信号
#忽略信号的操作
trap '' 信号
#恢复原信号的操作
trap '-' 信号
#列出自定义信号操作
trap -p
#当脚本退出时,执行finish函数
trap finish EXIT  

当脚本正常或异常退出时,也会执行finish函数 

退出了在屏幕显示finish并且在 /root/finish.log追加finish

finish(){    
echo finish| tee -a /root/finish.log
}
trap finish exit
while true ;do
echo running
sleep 1
done

创建临时文件 mktemp

mktemp 命令用于创建并显示临时文件,可避免冲突

root@CentOS wang]#mktemp 
/tmp/tmp.clr8lTS870

-d #创建临时目录
-p DIR或--tmpdir=DIR #指明临时文件所存放目录位置

实例

[root@CentOS wang]#mktemp 123XXX
123ooz
[root@CentOS wang]#mktemp XXX.log
uQk.log

安装复制文件 install

install 功能相当于cp,chmod,chown,chgrp ,mkdir 等相关工具的集合

-m MODE,默认755
-o OWNER
-g GROUP
-d DIRNAME 目录

交互式转化批处理工具 expect 

 expect 是由Don Libes基于 Tcl( Tool Command Language )语言开发的,主要应用于自动化交互式操作的场景

可以将交互过程如:ssh登录,ftp登录等写在一个脚本上,使之自动化完成

-c:从命令行执行expect脚本,默认expect是交互地执行的
-d:可以调试信息

expect中相关命令

  • spawn 启动新的进程
  • expect 从进程接收字符串
  • send 用于向进程发送字符串
  • interact 允许用户交互
  • exp_continue 匹配多个字符串在执行动作后加此命令 

单一分支模式语法:  匹配到hi后,会输出“you said hi”,并换行

[root@centos8 test]#expect
expect1.1> expect "hi" {send "You said hi\n"}
hahahixixi
You said hi

多分支模式语法:

[root@centos8 ~]#expect
expect1.1> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n"
} "bye" { send "Good bye\n" }
hehe
Hehe yourself
expect1.2> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n"
} "bye" { send "Good bye\n" }
bye
Good bye
expect1.3> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n"
} "bye" { send "Good bye\n" }
hi
You said hi
expect1.4>

[root@centos8 ~]#expect
expect1.1> expect {
+> "hi" { send "You said hi\n"}
+> "hehe" { send "Hehe yourself\n"}
+> "bye" { send " Good bye\n"}
+> }
bye
Good bye
非交互式复制文件    不是shell不能用bash
#!/usr/bin/expect
spawn scp /etc/redhat-release 10.0.0.7:/data
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "magedu\n" }
}
expect eof


自动登录
#!/usr/bin/expect
spawn ssh 10.0.0.7
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "magedu\n" }
}
interact
expect 变量
#!/usr/bin/expect
set ip 10.0.0.7      #就是shell的ip=10.0.0.7  
set user root         
set password magedu
set timeout 10       #等待10秒
spawn ssh $user@$ip    #spawn交互
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
interact
expect 位置参数 
[root@centos8 ~]#cat expect4
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
interact
[root@centos8 ~]#./expect4 10.0.0.7 root magedu
shell脚本调用 expect
#!/bin/bash
ip=$1
user=$2
password=$3
expect <<EOF
set timeout 20
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
expect "]#" { send "useradd hehe\n" }
expect "]#" { send "echo magedu |passwd --stdin hehe\n" }
expect "]#" { send "exit\n" }
expect eof
EOF
#./ssh5.sh 192.168.8.10 root magedu
shell脚本利用循环调用expect在CentOS和Ubuntu上批量创建用户
NET=10.0.0
user=root
password=magedu
IPLIST="
7
18
101
"
for ID in $IPLIST;do
ip=$NET.$ID
expect <<EOF
set timeout 20
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
expect "#" { send "useradd test\n" }
expect "#" { send "exit\n" }
expect eof
EOF
done

 

NET=10.0.0
user=root
password=magedu
IPLIST="
7
18
"
for ID in $IPLIST ;do
ip=$NET.$ID
expect <<EOF
set timeout 20
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
expect "#" { send "sed -i 's/^SELINUX=enforcing/SELINUX=disabled/'
/etc/selinux/config\n" }
expect "#" { send "setenforce 0\n" }
expect "#" { send "exit\n" }
expect eof
EOF
done

数组

  • 变量:存储单个元素的内存空间
  • 数组:存储多个元素的连续的内存空间,相当于多个变量的集合

declare -a                  显示全部数组   

echo ${#alpha[@]}    显示数组的个数

[root@CentOS wang]#read -a menu
zhangsan lisi wangwu zhaoliu         
[root@CentOS wang]#echo menu
menu

[root@CentOS wang]#declare -a
declare -a menu='([0]="zhangsan" [1]="lisi" [2]="wangwu" [3]="zhaoliu")'

[root@CentOS wang]#echo ${menu[*]}
zhangsan lisi wangwu zhaoliu
[root@CentOS wang]#echo ${menu[1]}
lisi
[root@CentOS wang]#echo ${menu[0]}
zhangsan
删除数组
[root@centos8 ~]#echo ${title[*]}
ceo coo cto
[root@centos8 ~]#unset title[1]
[root@centos8 ~]#echo ${title[*]}
ceo cto

[root@centos8 ~]#unset title
[root@centos8 ~]#echo ${title[*]}

[root@centos8 ~]#

数组数据切片处理 

[root@centos8 ~]#num=({0..10})
[root@centos8 ~]#echo ${num[*]:2:3}
2 3 4
[root@centos8 ~]#echo ${num[*]:6}
6 7 8 9 1

向数组中追加元素: 

[root@CentOS wang]#num=({0..5})
[root@CentOS wang]#echo ${#num[@]}
6
[root@CentOS wang]#num[6]=6
[root@CentOS wang]#echo ${#num[@]}
7
[root@CentOS wang]#num[${#num[@]}]=7
[root@CentOS wang]#echo ${#num[@]}
8
[root@CentOS wang]#echo ${num[@]}
0 1 2 3 4 5 6 7
[root@CentOS wang]#echo ${num[-2]}
6

生成10个随机数保存于数组中,并找出其最大值和最小值

#!/bin/bash
declare -i min max
declare -a nums
for ((i=0;i<10;i++));do
nums[$i]=$RANDOM
[ $i -eq 0 ] && min=${nums[0]} && max=${nums[0]}&& continue
[ ${nums[$i]} -gt $max ] && max=${nums[$i]} && continue
[ ${nums[$i]} -lt $min ] && min=${nums[$i]}
done
echo "All numbers are ${nums[*]}"
echo Max is $max
echo Min is $min

基于模式取子串

#其中word可以是指定的任意字符,自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字
符串开头至第一次出现word字符串(含)之间的所有字符,即懒惰模式,以第一个word为界删左留右
${var#*word}
#从var变量的值中删除以word开头的部分
${var#word}
#同上,贪婪模式,不同的是,删除的是字符串开头至最后一次由word指定的字符之间的所有内容,即贪婪模
式,以最后一个word为界删左留右
${var##*word}
${var##word} 

[root@centos8 ~]#file="var/log/messages"
[root@centos8 ~]#echo ${file#*/}
log/messages
[root@centos8 ~]#echo ${file##*/}
messages
从右往左
[root@CentOS wang]#echo ${file%%/*}
var
[root@CentOS wang]#echo ${file%/*}
var/log

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值