美文网首页
shell编程学习笔记(二)

shell编程学习笔记(二)

作者: dev_winner | 来源:发表于2020-10-25 16:07 被阅读0次
  • 内置命令:shift:使位置参数向左移动,默认移动1位,例如:shift 1
#!/bin/env bash
sum=0
while [ $# -ne 0 ]
  do
    let sum=$sum+$1 # 始终加上第1个位置的参数
    shift(将位置参数向左移动1位)
  done
echo sum=$sum
---------------------------------------------------------------------
[root@localhost myshell]# vim shift.sh
[root@localhost myshell]# chmod +x shift.sh 
[root@localhost myshell]# ./shift.sh 
sum=0
[root@localhost myshell]# ./shift.sh 1 2 3
sum=6
[root@localhost myshell]# yum list | grep expect
expect.x86_64                               5.45-14.el7_1              base     
expect-devel.i686                           5.45-14.el7_1              base     
expect-devel.x86_64                         5.45-14.el7_1              base     
expectk.x86_64                              5.45-14.el7_1              base     
pexpect.noarch                              2.3-11.el7                 base     
[root@localhost myshell]# yum -y install expect(安装 expect 程序)
[root@localhost myshell]# rpm -ql expect(列出expect安装包安装的文件)
  • expect是一门tcl(Tool Command Language)工具命令语言,其可以实现登录到远程服务器过程中自动应答。
  • exp_continue附加于某个expect判断项之后,可以使该项被匹配后,还能继续匹配该expect判断语句内的其他项。
#!/usr/bin/env expect
# 定义变量:set key value
set ip 192.168.211.141
set password 123456
set timeout 5 # 定义超时时间
# 开启一个程序
spawn ssh root@$ip
# 捕获相关内容
expect {
  "(yes/no)?" { send "yes\r";exp_continue } # \r表示回车执行该命令
  "password:" { send "$password\r" }
}
# 让终端处于交互状态,即会保持在终端而不会退回到原终端
interact
------------------------------------------------------------------------
[root@localhost myshell]# vim expect1.sh 
[root@localhost myshell]# ./expect1.sh 或者 expect -f expect1.sh 
spawn ssh root@192.168.211.141
root@192.168.211.141's password: 
Last login: Sun Oct 25 15:56:57 2020 from 192.168.211.146
[root@hadoop ~]# logout
Connection to 192.168.211.141 closed.
------------------------------------------------------------------------
#!/usr/bin/env expect
# 定义变量,set key value
set ip 192.168.211.141
set password 123456
set timeout 5
# 开启一个程序
spawn ssh root@$ip
# 捕获相关内容
expect {
  "(yes/no)?" { send "yes\r";exp_continue }
  "password:" { send "$password\r" }
}
expect "#"
send "rm -rf /tmp/*\r"
send "hostname\r"
send "date +%F\r"
send "touch /tmp/file{1..3}\r"
expect eof # 表示交互结束,退回到原用户
-------------------------------------------------------------------------
[root@localhost myshell]# ./expect1.sh 
spawn ssh root@192.168.211.141
root@192.168.211.141's password: 
Last login: Sun Oct 25 16:18:28 2020 from 192.168.211.146
[root@hadoop ~]# rm -rf /tmp/*
[root@hadoop ~]# hostname
hadoop
[root@hadoop ~]# date +%F
2020-10-25
[root@hadoop ~]# touch /tmp/file{1..3}
[root@hadoop ~]# [root@localhost myshell]# (自动退出连接远程会话的终端程序)
[root@hadoop tmp]# ll
总用量 0
-rw-r--r--. 1 root root 0 10月 25 16:18 file1
-rw-r--r--. 1 root root 0 10月 25 16:18 file2
-rw-r--r--. 1 root root 0 10月 25 16:18 file3
---------------------------------------------------------------------------
#!/bin/env expect
# 使用位置参数
set ip [ lindex $argv 0 ]
set password [ lindex $argv 1 ]
set timeout 5
# 开启一个程序
spawn ssh root@$ip
# 捕获相关内容
expect {
  "(yes/no)?" { send "yes\r";exp_continue }
  "password:" { send "$password\r" }
}
interact
---------------------------------------------------------------------------
[root@localhost myshell]# ./expect2.sh 192.168.211.141 123456
spawn ssh root@192.168.211.141
root@192.168.211.141's password: 
Last login: Sun Oct 25 16:19:53 2020 from 192.168.211.146
[root@hadoop ~]# logout
Connection to 192.168.211.141 closed.
[root@localhost myshell]# cat 1.txt 
10.1.1.1 stu1
[root@localhost myshell]# read ip password < 1.txt (将文件1.txt中的第一行内容按格式赋值给变量ip和password)
[root@localhost myshell]# echo $ip $password 
10.1.1.1 stu1
[root@localhost myshell]# cat 1.txt 
10.1.1.1 stu1
10.1.1.2 stu2
[root@localhost myshell]# while read ip password;do echo $ip $password;done < 1.txt 
10.1.1.1 stu1
10.1.1.2 stu2
  • 在多台服务器上各创建1个用户(shell和expect结合使用):
#!/bin/env bash
# 循环在指定服务器上创建用户和删除/tmp目录下的所有文件
while read ip password
  do
    /usr/bin/expect <<END &>/dev/null
    spawn ssh root@$ip
    expect {
          "(yes/no)?" { send "yes\r";exp_continue }
          "password:" { send "$password\r" }
    }
    expect "#" { send "useradd yy1;rm -rf /tmp/*;logout\r" }
    expect eof
END # 注意 END 需要顶格写
    echo "服务器:$ip 已完成创建用户!"       
  done < ip.txt
------------------------------------------------------------------------------
[root@localhost myshell]# vim expect3.sh
[root@localhost myshell]# chmod +x expect3.sh 
[root@localhost myshell]# cat ip.txt 
192.168.211.141 123456
192.168.211.156 123456
[root@localhost myshell]# ./expect3.sh 
服务器:192.168.211.141 已完成创建用户yy1!
服务器:192.168.211.156 已完成创建用户yy1!
[root@hadoop tmp]# id yy1(第一个服务器)
uid=1002(yy1) gid=1002(yy1) 组=1002(yy1)
[root@openstack ~]# id yy1(第二个服务器)
uid=1871(yy1) gid=1871(yy1) groups=1871(yy1)
  • 运维人员实现批量推送公钥到内网主机:①管理员root创建yunwei用户和安装expect软件包,编写脚本文件(normal.sh)
#!/bin/env bash
# 判断 jumper 上的 yunwei 账号是否存在
{
  id yunwei
  [ $? -ne 0 ] && useradd yunwei && echo 123 | passwd --stdin yunwei
} &>/dev/null
# 判断 expect 程序是否安装
rpm -q expect
[ $? -ne 0 ] && yum -y install expect && echo "expect软件包已安装成功!"
--------------------------------------------------------------------------------
[root@localhost myshell]# vim normal.sh
[root@localhost myshell]# chmod +x normal.sh 
[root@localhost myshell]# userdel -r yunwei
[root@localhost myshell]# rpm -e expect(卸载 expect 软件包)
[root@localhost myshell]# ./normal.sh 
未安装软件包 expect 
已加载插件:fastestmirror, langpacks
......
完毕!
expect软件已成功安装!
[root@localhost myshell]# rpm -q expect
expect-5.45-14.el7_1.x86_64
  • ②运维人员检查公钥是否存在,哪些内网主机可以ping通,并将公钥推送到能ping通的内网主机,编写脚本文件:(push_public_key.sh)
#!/bin/env bash
home_dir=/home/yunwei
# 判断 yunwei 用户的密钥对是否存在
[ ! -f $home_dir/.ssh/id_rsa.pub ] && ssh-keygen -P '' -f $home_dir/.ssh/id_rsa &>/dev/null
# 循环检查局域网内主机的网络并对连通的主机进行公钥推送
ip_txt=$home_dir/ip.txt
for i in `cat $ip_txt` # 读取文件中每一行内容
  do
    ip=`echo $i | cut -d : -f1`
    password=`echo $i | cut -d: -f2`
    ping -c1 $ip &>/dev/null
    if [ $? -eq 0 ];then
        echo $ip >> ~/ip_up.txt
        /usr/bin/expect <<-END
        set timeout 10
        spawn ssh-copy-id root@$ip # 开启一个程序,将公钥推送到指定内网主机
        expect "(yes/no)?" { send "yes\r";exp_continue }
        expect "password:" { send "$password\r" }
        expect eof
        END # 注意 END 左边为一个 tab 制表符:\t
    else
        echo $ip >> $home_dir/ip_down.txt
    fi
  done
-----------------------------------------------------------------
[yunwei@localhost ~]$ cat ip.txt 
192.168.211.156:123456
192.168.211.141:123456
[yunwei@localhost ~]$ chmod +x push_public_key.sh
[yunwei@localhost ~]$ bash -x push_public_key.sh
[yunwei@localhost ~]$ bash -x push_public_key.sh 
+ home_dir=/home/yunwei
+ '[' '!' -f /home/yunwei/.ssh/id_rsa.pub ']'
+ ssh-keygen -P '' -f /home/yunwei/.ssh/id_rsa
......
Now try logging into the machine, with:   "ssh 'root@192.168.211.141'"
and check to make sure that only the key(s) you wanted were added.

[yunwei@localhost ~]$ ll
总用量 12
-rw-rw-r--. 1 yunwei yunwei  46 10月 25 21:17 ip.txt
-rw-rw-r--. 1 yunwei yunwei  64 10月 25 22:05 ip_up.txt
-rwxrwxr-x. 1 yunwei yunwei 723 10月 25 22:05 push_public_key.sh
[yunwei@localhost ~]$ cat ip_up.txt 
192.168.211.156
192.168.211.141
[yunwei@localhost ~]$ ll .ssh/
总用量 12
-rw-------. 1 yunwei yunwei 1675 10月 25 22:05 id_rsa
-rw-r--r--. 1 yunwei yunwei  410 10月 25 22:05 id_rsa.pub
-rw-r--r--. 1 yunwei yunwei  354 10月 25 22:05 known_hosts
[root@hadoop .ssh]# ll(服务器ip为:192.168.211.141)
总用量 4
-rw-------. 1 root root 410 10月 25 22:05 authorized_keys
[root@openstack .ssh]# ll(服务器ip为:192.168.211.156)
total 4
-rw------- 1 root root 410 Oct 25 22:05 authorized_keys
--------------------------------------------------------------------
#!/bin/env bash
# 测试验证公钥是否推送成功
remote_ip=`tail -1 ~/ip_up.txt`
ssh root@$remote_ip hostname &>/dev/null
test $? -eq 0 && echo "成功推送公钥完毕!"
--------------------------------------------------------------------
[yunwei@localhost ~]$ vim test_ssh.sh
[yunwei@localhost ~]$ chmod +x test_ssh.sh 
[yunwei@localhost ~]$ ./test_ssh.sh 
成功推送公钥完毕!
  • 使用visudo打开sudo配置文件来管理用户的sudo权限:
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
yunwei  ALL=(root)      NOPASSWD:ALL,!/sbin/shutdown,!/sbin/init,!/bin/rm -rf /
--------------------------------------------------------------------------------------------
1、第一个字段 yunwei 指定的是用户:用户名或别名。每个用户设置一行,多个用户设置多行,也可将多个用户设置成一个别名后再进行设置。
2、第二个字段 ALL 指定用户所在的主机:ip或主机名,表示该sudo设置只在该主机上生效,默认限制的是本机,ALL表示在所有主机上都生效!
3、第三个字段 (root) 括号里指定以什么用户身份使用 sudo,即使用sudo后可以享有root账号下所有权限。若要排除个别用户,则可在括号内设置,如 ALL=(ALL,!oracle,!pos)。
4、第四个字段 ALL 指定的是执行的命令:即使用 sudo 后可以执行所有命令。除了设置不能关机和删除根内容以外,也可设置别名。NOPASSWD:ALL 表示使用sudo后不需要输入密码。
5、也可以授权给一个用户组:%admin ALL=(ALL) ALL  表示 admin 组里的所有成员都可以在任何主机上以任何用户身份执行任何命令。
  • 普通数组:只能使用整数作为数组索引。如:array[0]=v1
  • 关联数组:可以使用字符串作为数组索引。
  • 普通数组的定义,一次赋予多个值:数组名=(值1 值2 值3 ...),如:将文件中按空格隔开的字符串内容赋值给array1数组:array1=($(cat /etc/passwd))array4=(1 2 3 4 "hello world" [10]=linux)array3=(harry amy jack "Miss Hou")
  • 获取某个下标的数组元素:${数组名[元素下标]}
  • 查看所有普通数组:declare -a
  • 查看所有关联数组:declare -A
  • 获取数组中所有元素:echo ${array[*]}echo ${array[@]}
  • 获取数组中元素总个数:echo ${#array[*]}
  • 获取数组中元素的索引下标:echo ${!array[@]}
  • 访问指定的子数组:echo ${array[@]:1:2}(1代表从下标为1的元素开始获取;2代表获取后面几个元素)。
[root@localhost myshell]# names=(harry jack tom sarsh)
[root@localhost myshell]# echo ${names[*]}
harry jack tom sarsh
[root@localhost myshell]# echo ${names[@]}
harry jack tom sarsh
[root@localhost myshell]# echo ${names[@]:1:2}(获取子数组所有元素)
jack tom
[root@localhost myshell]# echo ${#names[*]}(获取数组中元素总个数)
4
[root@localhost myshell]# echo ${!names[*]}(获取每个元素对应的数组索引)
0 1 2 3
  • 关联数组的定义:①首先要声明关联数组:declare -A asso_array1;②数组元素赋值:一次赋一个值:数组名[索引or下标]=变量值,如:asso_array1[linux]=one;一次赋多个值:asso_array2=([name1]=harry [name2]=jack [name3]=amy [name4]="Miss Hou")。注意:关联数组下标是无序的。建议数组下标不要带空格!
[root@localhost myshell]# declare -A asso_array1
[root@localhost myshell]# asso_array1[linux]=one
[root@localhost myshell]# asso_array1[java]=two
[root@localhost myshell]# declare -A
declare -A BASH_ALIASES='()'
declare -A BASH_CMDS='()'
declare -A asso_array1='([java]="two" [linux]="one" )'
[root@localhost myshell]# echo ${asso_array1[*]}
two one
[root@localhost myshell]# echo ${!asso_array1[*]}
java linux # 从这里可以看出初始化顺序不一定是打印顺序,即元素下标存储是无序的
[root@localhost myshell]# echo ${#asso_array1[*]}
2
[root@localhost myshell]# declare -A asso_array2
[root@localhost myshell]# asso_array2=([name1]=harry [name2]=jack [name3]=amy [name4]="Miss Hou")
[root@localhost myshell]# declare -A
declare -A BASH_ALIASES='()'
declare -A BASH_CMDS='()'
declare -A asso_array1='([java]="two" [linux]="one" )'
declare -A asso_array2='([name3]="amy" [name2]="jack" [name1]="harry" [name4]="Miss Hou" )'
[root@localhost myshell]# echo ${asso_array2[*]}
amy jack harry Miss Hou
[root@localhost myshell]# echo ${!asso_array2[*]}
name3 name2 name1 name4
[root@localhost myshell]# echo ${#asso_array2[*]}
4
  • 获取某个文件名:basename 文件的绝对路径名
  • 获取某个文件所在的目录名:dirname 文件的绝对路径名
  • 变量值的删除匹配模式:
1个"%"代表从右往左去掉一个/key/
2个"%"代表从右往左最大去掉/key/
1个"#"代表从左往右去掉一个/key/
2个"#"代表从左往右最大去掉/key/
-----------------------------------------------
[root@localhost myshell]# url=www.taobao.com
[root@localhost myshell]# echo ${#url} (获取变量的长度)
14
[root@localhost myshell]# echo ${url#*.}(从左往右去掉一个/*./)
taobao.com
[root@localhost myshell]# echo ${url##*.}(从左往右最大去掉/*./)
com
[root@localhost myshell]# echo ${url%.*}(从右往左去掉一个/.*/)
www.taobao
[root@localhost myshell]# echo ${url%%.*}(从右往左最大去掉/.*/)
www
[root@localhost myshell]# A=/root/myshell/web_server_check.sh 
[root@localhost myshell]# echo $A
/root/myshell/web_server_check.sh
[root@localhost myshell]# dirname $A(获取文件名)
/root/myshell
[root@localhost myshell]# basename $A(获取文件所在的目录名)
web_server_check.sh
  • 统计web服务的不同连接状态个数,编写脚本(count_web_state.sh):
#!/bin/env bash
# 统计每个连接状态的个数
declare -A array1
states=`ss -ant | grep 80 | cut -d' ' -f1`
for i in $states
  do
        let array1[$i]++
  done
# 通过遍历数组中的所有索引,将索引和对应的值打印出来
for j in ${!array1[@]}
  do
        echo $j:${array1[$j]}
  done
-----------------------------------------------------------------------
[root@localhost myshell]# vim count_web_state.sh
[root@localhost myshell]# chmod +x count_web_state.sh 
[root@localhost myshell]# bash -x count_web_state.sh 
+ declare -A array1
++ ss -ant
++ grep 80
++ cut '-d ' -f1
+ states=LISTEN
+ for i in '$states'
+ let 'array1[LISTEN]++'
+ for j in '${!array1[@]}'
+ echo LISTEN:1
LISTEN:1
[root@localhost myshell]# netstat -ntp
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 192.168.211.146:22      192.168.211.1:14311     ESTABLISHED 3509/sshd: root@pts 
[root@localhost myshell]# netstat -nltp | grep 80
tcp6       0      0 :::80                   :::*                    LISTEN      6845/httpd          
[root@localhost myshell]# netstat -natp | grep 80
tcp6       0      0 :::80                   :::*                    LISTEN      6845/httpd          
[root@localhost myshell]# ss -natp | grep :80
LISTEN     0      128       [::]:80                    [::]:*                   users:(("httpd",pid=6850,fd=4),("httpd",pid=6849,fd=4),("httpd",pid=6848,fd=4),("httpd",pid=6847,fd=4),("httpd",pid=6846,fd=4),("httpd",pid=6845,fd=4))
  • netstat用于显示网络连接,路由表,接口状态,伪装连接,网络链路信息和组播成员组:netstat [选项] | grep 端口号
  • 常用选项:
-a(--all):显示所有正在或不在侦听的套接字。加上 --interfaces 选项将显示没有标记的接口。
-t(--tcp):显示tcp相关选项。
-u(--udp):显示udp相关选项。
-n(--numeric):显示数字形式地址而不是去解析主机、端口或用户名。
-l( --listening):只显示正在侦听的套接字(这是默认的选项)。
-p(--program):显示套接字所属进程的PID和名称。
  • case语句为多重匹配语句,pattern表示需要匹配的模式。
case var in # 定义变量,var 代表是变量名
pattern 1)   # 模式1:用 | 或 or 分割多个候选值
    command1          
    ;; # 两个分号代表该命令执行完后就结束
pattern 2)
    command2
    ;;
pattern 3)
    command3
    ;;
        *)  # default:不满足以上模式,默认执行 *) 下面的命令
    command4
    ;;
esac # esac表示 case 语句结束
  • 实战:执行脚本命令时传不同值完成不同的事情。
#!/bin/env bash
case $1 in
        start|S)
          echo "service is running..."
          ;;
        stop|T)
          echo "service is stopped..."
          ;;
        reload|R)
          echo "service is restart..."
          ;;
        *)
          echo "请输入你要执行的动作!"
          ;;
esac
---------------------------------------------------------------------
[root@localhost myshell]# vim case1.sh
[root@localhost myshell]# chmod +x case1.sh 
[root@localhost myshell]# ./case1.sh S
service is running...
[root@localhost myshell]# ./case1.sh T
service is stopped...
[root@localhost myshell]# ./case1.sh 
请输入你要执行的动作!
[root@localhost myshell]# ./case1.sh R
service is restart...
[root@localhost myshell]# cat 
hello
hello
world 
world(ctrl+d 结束输入)
[root@localhost myshell]# cat <<END
> hello
> world
> END(输入END结束输入)
hello
world
[root@localhost myshell]# su - yunwei <<END
> echo hello
> END
上一次登录:一 10月 26 16:01:32 CST 2020
hello
[root@localhost myshell]# (仍留在当前用户)
  • 实战:模拟一个多任务维护界面,当执行程序时先显示总菜单,然后进行选择后做出相应的维护操作。
#!/bin/env bash
menu(){
cat <<-EOF
        h 显示命令帮助
        f 显示磁盘分区
        d 显示磁盘挂载
        m 查看内存使用
        u 查看系统负载
        q 退出程序
        EOF
}
# 函数调用
menu
while true
do
# 用户选择需要操作的内容
read -p "请选择需要执行的动作(help h):" action
clear
# 函数调用
menu
case $action in
        h|help)
        menu
        ;;
        f)
        # fdisk -l
        lsblk
        ;;
        d)
        df -h
        ;;
        m)
        free -m
        ;;
        u)
        uptime
        ;;
        q)
        exit
        ;;
esac
done
  • 函数的定义:
函数名() {
  函数体(一堆命令的集合)
}
-----------------------------
function 函数名() {
  函数体(一堆命令的集合)
}
-----------------------------------------------------------
[root@localhost myshell]# source fun1.sh (source 读取一下文件,函数的作用域只对当前终端有效)
[root@localhost myshell]# cat fun1.sh 
#!/bin/env bash
hello() {
    echo hello world
}
function work() {
    rm -rf /tmp/*
    touch /tmp/file{1..3}
}
[root@localhost myshell]# hello
hello world
[root@localhost myshell]# work
[root@localhost myshell]# ll /tmp/
总用量 0
-rw-r--r--. 1 root root 0 10月 26 16:42 file1
-rw-r--r--. 1 root root 0 10月 26 16:42 file2
-rw-r--r--. 1 root root 0 10月 26 16:42 file3
  • 函数中return的作用:①return可以结束一个函数;②return默认返回函数中最后一个命令的状态值,也可以给定参数值,范围是0-256之间;③若没有return命令,函数则默认返回最后一个指令的退出状态值。
[root@localhost myshell]# vim fun1.sh 
[root@localhost myshell]# source fun1.sh 
[root@localhost myshell]# cat fun1.sh 
#!/bin/env bash
hello() {
    echo hello world
}
function work() {
    rm -rf /tmp/*
    touch /tmp/file{1..3}
    return 10  # 自定义返回最后一个命令执行后的状态值
}
[root@localhost myshell]# work 
[root@localhost myshell]# echo $?
10
[root@localhost myshell]# vim fun2.sh 
[root@localhost myshell]# source fun2.sh 
[root@localhost myshell]# cat fun2.sh 
#!/bin/env bash
# 菜单打印
menu(){
    cat <<-EOF
        h 显示命令帮助
        f 显示磁盘分区
        d 显示磁盘挂载
        m 查看内存使用
        u 查看系统负载
        q 退出程序
    EOF

}
hha(){
    echo $1
}
[root@localhost myshell]# hha 5555 444(执行某个函数时顺便传递位置参数)
5555
[root@localhost myshell]# su - stu1
[stu1@localhost ~]$ vim ~/.bashrc # 将函数定义到用户的环境变量中
[stu1@localhost ~]$ ls -a
.  ..  .bash_logout  .bash_profile  .bashrc  .cache  .config  .mozilla  .viminfo
[stu1@localhost ~]$ source ./.bashrc # 函数定义只在当前用户全局内有效:~/.bashrc,在任何用户全局内有效:/etc/bashrc)
[stu1@localhost ~]$ menu
        h 显示命令帮助
        f 显示磁盘分区
        d 显示磁盘挂载
        m 查看内存使用
        u 查看系统负载
        q 退出程序
  • 实战:①只允许yunwei用户通过跳板机远程连接后台的应用服务器做一些维护操作;②公司运维人员远程通过yunwei用户连接跳板机时,跳出以下菜单供选择;③当用户选择相应主机后,直接免密码登录成功;④若用户不输入则一直提示用户输入,直到用户选择退出为止。编写脚本文件(jumper-server.sh):
#!/bin/env bash
menu()
{
cat <<-EOF
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
        EOF
}
# 屏蔽以下信号,比如键入 ctrl+z 后不作反应
trap "" 1 2 3 19 20
# 调用函数来打印菜单
menu
#循环等待用户选择
while true
do
# 菜单选择,case...esac语句
read -p "请选择你要访问的主机:" host
case $host in
        1)
        ssh root@192.168.211.141
        ;;
        2)
        ssh root@192.168.211.156
        ;;
        h)
        clear;menu
        ;;
        q)
        exit
        ;;
esac
---------------------------------------------------------------------------
[yunwei@localhost ~]$ chmod +x jumper-server.sh
[yunwei@localhost ~]$ vim .bashrc
[root@localhost yunwei]# cat /home/yunwei/.bashrc 
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
~/jumper-server.sh # 当登录到 yunwei 账号时直接进入自定义的菜单选择模式
exit
[root@localhost myshell]# su - yunwei(切换到 yunwei 账号时自动执行自定义的脚本)
上一次登录:二 10月 27 14:58:10 CST 2020pts/1 上
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
请选择你要访问的主机:1
Last login: Tue Oct 27 15:18:27 2020 from 192.168.211.146
[root@hadoop ~]# pwd
/root
[root@hadoop ~]# logout
Connection to 192.168.211.141 closed.
请选择你要访问的主机:^Z^Z^Z^Z^Z^C^C(快捷键信号被屏蔽,键入后不作反应)
请选择你要访问的主机:q
[root@localhost myshell]# 
  • 运行shell脚本时,若键入快捷键Ctrl+cCtrl+x(x为其他字符),程序就会终止运行,但我们并不希望shell脚本在运行时被信号中断,此时就可以使用屏蔽信号手段,让程序忽略用户输入的信号指令,从而继续运行shell脚本程序:trap "commands" signal-list(当脚本收到signal-list清单内列出的信号时,trap命令执行双引号中的命令)
  • trap "" signal-list:指定一个空命令串,表示直接忽视给定的信号。
  • 使用kill -l查看信号列表:
1、SIGHUP:重新加载配置    
2、SIGINT:键盘中断^C
3、SIGQUIT:键盘退出
9、SIGKILL:强制终止
15、SIGTERM:终止(正常结束),缺省信号
18、SIGCONT:继续
19、SIGSTOP:停止
20、SIGTSTP:暂停^Z
  • 正则表达式:①元字符:具有特殊意义的专用字符,如:点(.) 星(*) 问号(?)等。②前导字符:位于元字符前面的字符:abc*,aooo.
  • 正则表达式中常用的元字符:
元字符 功能 备注
. 匹配除换行符以外的任意单个字符
* 前导字符出现0次或连续多次
.* 任意长度的字符 ab.*
^ 行首(以......开头) ^root
$ 行尾(以......结尾) bash$
^$ 空行
[] 匹配括号里任意单个字符或一组单个字符 [abc]
[^] 匹配不包含括号里任一单个字符或一组单个字符 [^abc]
^[] 匹配以括号里任意单个字符或一组单个字符开头 ^[abc]
^[^] 匹配不以括号里任意单个字符或一组单个字符开头 ^[^abc]
\< 取单词的头 \<hel
\> 取单词的尾 rld\>
\<\> 精确匹配 \<world\>
\{n\} 匹配前导字符连续出现n次 go\{2\}
\{n,\} 匹配前导字符至少出现n次 go\{2,\}
\{n,m\} 匹配前导字符出现n次与m次之间 go\{2,4\}
\(\) 保存被匹配的字符 一般用于搜索替换
\d 匹配数字(grep -P [0-9]
\w 匹配字母数字下划线(grep -P [a-zA-Z0-9_]
\s 匹配空格、制表符、换页符(grep -P [\t\r\n]
vim替换ip地址字符串
  • 扩展类正则表达式中常用的元字符:必须使用特定的命指令:grep -Eegrepsed -r
扩展元字符 功能 备注
+ 匹配1个或多个前导字符 bo+匹配boobo
? 匹配0个或1个前导字符 bo?匹配bbo
| 匹配a或b
() 组字符(看成整体) (my|your)self:表示匹配myselfyourself
{n} 前导字符重复n次 go{2}
{n,} 前导字符重复至少n次 go{2,}
{n,m} 前导字符重复n到m次 go{2,4}
[:lower:] 小写字母 [[:lower:]]{4,}
[:upper:] 大写字母 [[:upper:]]+
[:digit:] 数字 [[:digit:]]?
[:alnum:] 字母和数字字符 [[:alnum:]]+
[:alpha:] 所有字母(包括大小写字母) [[:alpha:]]{4}
[:blank:] 空格与制表符 [[:blank:]]*
[:punct:] 标点符号 [[:punct:]]
[:space:] 包括换行符,回车等在内的所有空白 [[:space:]]+
1、查找不以大写字母开头的行:
grep '^[^A-Z]' re.sh
grep -v '^[A-Z]' re.sh
grep '^[^[:upper:]]' re.sh
2、查找有数字的行:
grep '[0-9]' re.sh
grep -P '\d' re.sh
3、查找数字相邻为字母的行:
grep -E '[0-9][a-zA-Z]|[a-zA-Z][0-9]' re.sh
4、查找不以字符r开头的行:
grep -v '^r' re.sh
grep '^[^r]' re.sh
5、查找以数字开头的行:
grep '^[0-9]' re.sh
6、查找以大写字母开头的行:
grep '^[A-Z]' re.sh
7、查找以小写字母开头的行:
grep '^[a-z]' re.sh
8、查找以点结束的行:
grep '\.$' re.sh
9、查找不包行空行的所有行:
grep -v '^$' re.sh
10、查找完全匹配abc的行:
grep '\<abc\>' re.sh 
grep -w 'abc' re.sh
11、查找A后有三个数字的行:
grep -E 'A[0-9]{3}' re.sh
grep 'A[0-9]\{3\}' re.sh
12、统计root在/etc/passwd里出现了几次:
grep -o 'root' /etc/passwd | wc -l
13、找出主机网卡 ens32 的IP地址、广播地址、子网掩码:
ifconfig ens32 | grep -o -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
ifconfig ens32 | grep -o -E '([0-9]{1,3}\.){3}[0-9]{1,3}'
ifconfig ens32 | grep -o -P '(\d{1,3}\.){3}\d{1,3}'
14、找出一行中全部是数字的所有行:
grep -E '^[0-9]+$' re.sh
15、找出邮箱地址的行:
grep -E '^[0-9a-zA-Z]+@[a-z0-9]+\.[a-z]+$' re.sh

相关文章

网友评论

      本文标题:shell编程学习笔记(二)

      本文链接:https://www.haomeiwen.com/subject/dkggmktx.html