Ubuntu系统网络配置及shell脚本编程之函数数组等用法详解
1、Ubuntu系统网络配置总结
1.1 主机名
修改主机名
root@ubuntu20:/home/dong# hostname ubuntu20 root@ubuntu20:/home/dong# hostnamectl set-hostname ubuntu20.magedu.cn root@ubuntu20:/home/dong# hostname ubuntu20.magedu.cn root@ubuntu20:/home/dong# cat /etc/hostname ubuntu20.magedu.cn root@ubuntu20:/home/dong# echo $HOSTNAME #不能立即生效,重新登录后生效 ubuntu20 root@ubuntu20:/home/dong# logout bash: logout: not login shell: use `exit' root@ubuntu20:/home/dong# exit exit dong@ubuntu20:~$ su Password: root@ubuntu20:/home/dong# echo $HOSTNAME ubuntu20.magedu.cn
1.2 网卡名称
默认ubuntu的网卡名称和 CentOS 7 类似,如:ens33,ens38等
修改网卡名称为传统命名方式:
#查看网卡默认名称为ens系列 root@ubuntu20:~# ip a |grep ens 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 inet 192.168.100.180/24 brd 192.168.100.255 scope global ens33 #查看配置文件 root@ubuntu20:~# cat /etc/default/grub GRUB_DEFAULT=0 GRUB_TIMEOUT_STYLE=hidden GRUB_TIMEOUT=0 GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian` GRUB_CMDLINE_LINUX_DEFAULT="maybe-ubiquity" GRUB_CMDLINE_LINUX="" 1)修改配置文件GRUB_CMDLINE_LINUX root@ubuntu20:~# sed -i.bak '/^GRUB_CMDLINE_LINUX=/s#"$#net.ifnames=0"#' /etc/default/grub 2)生成新的grub.cfg文件 root@ubuntu20:~# grub-mkconfig -o /boot/grub/grub.cfg Sourcing file `/etc/default/grub' Sourcing file `/etc/default/grub.d/init-select.cfg' Generating grub configuration file ... Found linux image: /boot/vmlinuz-5.4.0-42-generic Found initrd image: /boot/initrd.img-5.4.0-42-generic done #或者 root@ubuntu20:~# update-grub root@ubuntu20:~# grep net.ifnames /boot/grub/grub.cfg linux /vmlinuz-5.4.0-42-generic root=/dev/mapper/ubuntu--vg-ubuntu--lv ro net.ifnames=0 maybe-ubiquity linux /vmlinuz-5.4.0-42-generic root=/dev/mapper/ubuntu--vg-ubuntu--lv ro net.ifnames=0 maybe-ubiquity linux /vmlinuz-5.4.0-42-generic root=/dev/mapper/ubuntu--vg-ubuntu--lv ro recovery nomodeset net.ifnames=0 dong@ubuntu20:~$ #重启后生效 root@ubuntu20:~# reboot 3)重启后,eth0无ip地址,替换原配置的接口名称 root@ubuntu20:~# sed -i 's/ens33/eth0' /etc/netplan/00-installer-config.yaml root@ubuntu20:~# netplan apply #生效 root@ubuntu20:~# cat /etc/netplan/00-installer-config.yaml # This is the network config written by 'subiquity' network: ethernets: eth0: # dhcp: no addresses: [192.168.100.180/24] optional: true gateway4: 192.168.100.2 nameservers: addresses: [192.168.100.2] version: 2 root@ubuntu20:~# ip a |grep eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 inet 192.168.100.180/24 brd 192.168.100.255 scope global eth0
1.3 Ubuntu网卡配置
官网文档:
帮助文档:https://help.ubuntu.com/
https://help.ubuntu.com/lts/serverguide/network-configuration.html.zh-CN
网络配置文档:https://ubuntu.com/server/docs/network-configuration
网络配置文件:yaml格式
1)- 列表:表示多个成员或[ ]
2)键(变量名):值
3)不同层级有缩进,而且统一
1.3.1 配置自动获取IP
范例:
root@ubuntu20:~# cat /etc/netplan/00-installer-config.yaml # This is the network config written by 'subiquity' network: ethernets: eth0: dhcp4: yes #addresses: [192.168.100.180/24] #optional: true #gateway4: 192.168.100.2 #nameservers: # addresses: [192.168.100.2] version: 2 #修改网卡配置文件后需执行命令生效: root@ubuntu20:~# netplan apply root@ubuntu20:~# ip a|grep eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 inet 192.168.100.128/24 brd 192.168.100.255 scope global dynamic eth0
1.3.2 配置静态IP
范例:
root@ubuntu20:~# cat /etc/netplan/00-installer-config.yaml # This is the network config written by 'subiquity' network: ethernets: eth0: #dhcp4: yes addresses: [192.168.100.128/24,192.168.100.180/24] optional: true gateway4: 192.168.100.2 nameservers: #search:[magedu.com,magedu.org] addresses: [192.168.100.2] version: 2 #或者用下面两行,两种格式不能混用 addresses: - 192.168.100.128/24 - 192.168.100.180/24 root@ubuntu20:~# ip a|grep eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 00:0c:29:02:81:56 brd ff:ff:ff:ff:ff:ff inet 192.168.100.128/24 brd 192.168.100.255 scope global eth0 inet 192.168.100.180/24 brd 192.168.100.255 scope global secondary eth0
查看ip和gateway
root@ubuntu20:/etc/apt# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 00:0c:29:02:81:56 brd ff:ff:ff:ff:ff:ff inet 192.168.100.128/24 brd 192.168.100.255 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.100.180/24 brd 192.168.100.255 scope global secondary eth0 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fe02:8156/64 scope link valid_lft forever preferred_lft forever
查看路由表route
#1)执行route -n root@ubuntu20:~# route -n #route没有安装,需安装net-tools文件 Command 'route' not found, but can be installed with: apt install net-tools root@ubuntu20:~# apt install net-tools Reading package lists... Done Building dependency tree Reading state information... Done The following NEW packages will be installed: net-tools 0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. Need to get 196 kB of archives. After this operation, 864 kB of additional disk space will be used. Err:1 http://mirrors.aliyun.com focal/main amd64 net-tools amd64 1.60+git20180626.aebd88e-1ubuntu1 404 Not Found [IP: 111.62.129.238 80] E: Failed to fetch http://mirrors.aliyun.com/pool/main/n/net-tools/net-tools_1.60+git20180626.aebd88e-1ubuntu1_amd64.deb 404 Not Found [IP: 111.62.129.238 80] E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing? #2)因aliyun源无法连通,更换为清华源 root@ubuntu20:/# cd /etc/apt root@ubuntu20:/etc/apt# cp sources.list sources.list.bak #编辑source.list,复制清华源 root@ubuntu20:/etc/apt# cat sources.list # 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释 deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse #3)更新 root@ubuntu20:/etc/apt# apt update #4)安装net-tools工具 root@ubuntu20:/etc/apt# apt install net-tools #5)查看路由表 root@ubuntu20:/etc/apt# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.100.2 0.0.0.0 UG 0 0 0 eth0 192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
查看DNS
dong@ubuntu20:~$ ll /etc/resolv.conf lrwxrwxrwx 1 root root 39 Jul 31 2020 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf dong@ubuntu20:~$ systemd-resolve --status Global LLMNR setting: no MulticastDNS setting: no DNSOverTLS setting: no DNSSEC setting: no DNSSEC supported: no DNSSEC NTA: 10.in-addr.arpa 16.172.in-addr.arpa 168.192.in-addr.arpa 17.172.in-addr.arpa 18.172.in-addr.arpa 19.172.in-addr.arpa 20.172.in-addr.arpa 21.172.in-addr.arpa 22.172.in-addr.arpa 23.172.in-addr.arpa 24.172.in-addr.arpa 25.172.in-addr.arpa 26.172.in-addr.arpa 27.172.in-addr.arpa 28.172.in-addr.arpa 29.172.in-addr.arpa 30.172.in-addr.arpa 31.172.in-addr.arpa corp d.f.ip6.arpa home internal intranet lan local private test Link 2 (eth0) Current Scopes: DNS DefaultRoute setting: yes LLMNR setting: yes MulticastDNS setting: no DNSOverTLS setting: no DNSSEC setting: no DNSSEC supported: no Current DNS Server: 192.168.100.2 DNS Servers: 192.168.100.2
1.3.3 配置多⽹卡静态IP和静态路由
1、多个网卡配置都在一个文件
root@ubuntu20:~# cat /etc/netplan/00-installer-config.yaml # This is the network config written by 'subiquity' network: ethernets: eth0: addresses: - 192.168.100.128/24 optional: true gateway4: 192.168.100.2 nameservers: #search:[magedu.com,magedu.org] addresses: [192.168.100.2] version: 2 ethernets: eth1: addresses: [172.16.100.128/24] #gateway4: 172.16.100.1 #nameservers: # addresses: [223.5.5.5,180.76.76.76] routes: - to: 10.10.100.0/24 via: 172.16.100.1 - to: 172.18.100.0/24 via: 172.16.100.1 - to: 172.19.100.0/24 via: 172.16.100.1 root@ubuntu20:~# netplan apply root@ubuntu20:~# ip a|grep eth 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 00:0c:29:02:81:56 brd ff:ff:ff:ff:ff:ff inet 192.168.100.128/24 brd 192.168.100.255 scope global eth0 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 00:0c:29:02:81:60 brd ff:ff:ff:ff:ff:ff inet 172.16.100.128/24 brd 172.16.100.255 scope global eth1 root@ubuntu20:~# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.100.2 0.0.0.0 UG 0 0 0 eth0 10.10.100.0 172.16.100.1 255.255.255.0 UG 0 0 0 eth1 172.16.100.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1 172.18.100.0 172.16.100.1 255.255.255.0 UG 0 0 0 eth1 172.19.100.0 172.16.100.1 255.255.255.0 UG 0 0 0 eth1 192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
2、每个网卡各自一个配置文件
root@ubuntu20:~# cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
ethernets:
eth0:
addresses:
- 192.168.100.128/24
optional: true
gateway4: 192.168.100.2
nameservers:
#search:[magedu.com,magedu.org]
addresses: [192.168.100.2]
version: 2
root@ubuntu20:~# cat /etc/netplan/01-eth1-config.yaml
# This is the network config written by 'subiquity'
network:
version: 2
ethernets:
eth1:
addresses: [172.16.100.128/24]
#gateway4: 172.16.100.1
nameservers:
addresses: [223.5.5.5,180.76.76.76]
routes:
- to: 10.10.100.0/24
via: 172.16.100.1
- to: 172.18.100.0/24
via: 172.16.100.1
- to: 172.19.100.0/24
via: 172.16.100.1
root@ubuntu20:~# netplan apply
root@ubuntu20:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:02:81:56 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.128/24 brd 192.168.100.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe02:8156/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:02:81:60 brd ff:ff:ff:ff:ff:ff
inet 172.16.100.128/24 brd 172.16.100.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe02:8160/64 scope link
valid_lft forever preferred_lft forever
root@ubuntu20:~# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.100.2 0.0.0.0 UG 0 0 0 eth0
10.10.100.0 172.16.100.1 255.255.255.0 UG 0 0 0 eth1
172.16.100.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
172.18.100.0 172.16.100.1 255.255.255.0 UG 0 0 0 eth1
172.19.100.0 172.16.100.1 255.255.255.0 UG 0 0 0 eth1
192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
root@ubuntu20:~#
2 函数介绍
- 函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程
- 它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分
函数和shell程序比较相似,区别在于
==Shell程序在子Shell中运行,而Shell函数在当前Shell中运行==。因此在当前Shell中,函数可对shell中的变量进行修改
2.1 管理函数
函数由两部分组成:函数名和函数体
帮助参看:help function
2.1.1 定义函数
格式:
#语法一: func_name (){ ...函数体... } #语法二: function func_name { ...函数体... } #语法三: function func_name () { ...函数体... }
定义函数范例:函数定义和调用在一个脚本中
1)创建一个关闭防火墙和selinux的函数 [root@repo-client scripts]# cat all_functions disable_firewall_selinux () { systemctl stop firewalld systemctl disable firewalld sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config setenforce 0 } disable_firewall_selinux #调用函数 #原来的selinux和firewall状态 [root@repo-client scripts]# cat /etc/selinux/config SELINUX=enforcing [root@repo-client scripts]# systemctl status firewalld Active: active (running) since Tue 2021-03-23 13:52:58 CST; 9min ago #执行函数,并查看结果 [root@repo-client scripts]# . all_functions [root@repo-client scripts]# systemctl status firewalld Active: inactive (dead) [root@repo-client scripts]# cat /etc/selinux/config SELINUX=disabled 2)创建centos7统一的repo [root@repo-client scripts]# cat all_functions yum_repo () { cd /etc/yum.repos.d/ mkdir backup -p mv *.repo backup cat > base.repo <<EOF [BaseOS-aliyun] name=centos7 repo-server BaseOS by aliyun baseurl=https://mirrors.aliyun.com/centos/7/os/x86_64/ gpgcheck=0 [epel] name=centos7 repo-server epel baseurl=https://mirrors.aliyun.com/epel/7/x86_64/ gpgcheck=0 [extras] name=centos7 repo-server extras baseurl=https://mirrors.aliyun.com/centos/7/extras/x86_64/ gpgcheck=0 EOF } yum_repo #查看原来的yum.repos.d目录中的文件 [root@repo-client yum.repos.d]# ls backup centos7-client.repo Centos-7.repo CentOS-Base.repo [root@repo-client scripts]# . all_functions mv: overwrite ‘backup/CentOS-Base.repo’? y [root@repo-client yum.repos.d]# ll total 4 drwxr-xr-x. 2 root root 235 Mar 23 14:20 backup -rw-r--r--. 1 root root 512 Mar 23 14:20 base.repo [root@repo-client yum.repos.d]# yum repolist repo id repo name status BaseOS-aliyun centos7 repo-server BaseOS by aliyun 10,072 epel centos7 repo-server epel 13,564 extras centos7 repo-server extras 460 repolist: 24,096
范例:函数定义和调用分开
1)函数定义在一个统一的脚本文件中,如all_functions; [root@repo-client scripts]# cat all_functions #1)停止防火墙和selinux的函数 disable_firewall_selinux () { systemctl stop firewalld systemctl disable firewalld sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config setenforce 0 } #2)定义yum源的函数 yum_repo () { ...同上...省略 } 2)调用函数时,编写相应的sh脚本,如只需要关闭防火墙和selinux,就编写这样一个脚本,就不执行其他的函数了 [root@repo-client scripts]# cat dis_firewall_selinux.sh #!/bin/bash #调用函数库 . all_functions #关闭防火墙和selinux disable_firewall_selinux 3)测试执行 [root@repo-client scripts]# . dis_firewall_selinux.sh
范例:安装常用软件的函数
1)该函数也定义在统一的脚本文件all_functions中 [root@repo-client scripts]# cat all_functions #1)关闭防火墙和selinux disable_firewall_selinux () { ...省略... } #2)统一yum源仓库 yum_repo () { ...省略... } #3)安装常用软件工具 install_packages () { PACKAGES=" vim tree autofs net-tools gcc make autoconf pcre pcre-devel openssl openssl-devel vim lrzsz tmux lsof tcpdump wget iotop " for i in $PACKAGES; do rpm -q $i &> /dev/null || yum -q -y install $i done } 2、编写安装脚本,测试 [root@repo-client scripts]# rpm -q vim lrzsz lsof gcc package vim is not installed package lrzsz is not installed package lsof is not installed package gcc is not installed [root@repo-client scripts]# . install_packages.sh ...安装过程省略... [root@repo-client scripts]# rpm -q vim lrzsz lsof gcc package vim is not installed lrzsz-0.12.20-36.el7.x86_64 lsof-4.87-6.el7.x86_64 gcc-4.8.5-44.el7.x86_64
范例:调用函数的简易运维菜单脚本
[root@centos7 scripts]# cat fun_menu.sh #!/bin/bash . all_functions PS3="请选择运维编号(1-4):" select MENU in 关闭防火墙和selinux 配置yum仓库 安装常用软件包 退出; do case $REPLY in 1) disable_firewall_selinux ;; 2) yum_repo ;; 3) install_packages ;; 4) exit ;; *) echo "输入错误,请重新输入" ;; esac done [root@centos7 scripts]# bash fun_menu.sh 1) 关闭防火墙和selinux 3) 安装常用软件包 2) 配置yum仓库 4) 退出 请选择运维编号(1-4):1 setenforce: SELinux is disabled 请选择运维编号(1-4):2 请选择运维编号(1-4):4 [root@centos7 scripts]#
2.1.2 查看函数
#查看当前已定义的函数名 declare -F #查看当前已定义的函数定义 declare -f #查看指定当前已定义的函数名 declare -f func_name #查看当前已定义的函数名定义 declare -F func_name [root@repo-client scripts]# declare -f disable_firewall_selinux () { systemctl stop firewalld; systemctl disable firewalld; sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config; setenforce 0 } yum_repo () { ...省略... } [root@repo-client scripts]# declare -F declare -f disable_firewall_selinux declare -f yum_repo
2.1.3 删除函数
unset func_name #删除函数
2.2 函数调用
范例1:函数体内执行的变量赋值,影响外面的变量值
[root@repo-client scripts]# cat test1 #变量赋值 test () { NAME=mage echo NAME=$NAME } [root@repo-client scripts]# . test1 #.或source是在当前shell中执行 [root@repo-client scripts]# test #函数内的变量赋值 NAME=mage [root@repo-client scripts]# NAME=wang #重新赋值 [root@repo-client scripts]# echo $NAME #显示 wang [root@repo-client scripts]# test #再次执行test函数 NAME=mage [root@repo-client scripts]# echo $NAME #再查看$NAME,是函数内的赋值;因函数内的变量和当前进程是同级关系,在同一个shell中,不是子进程。 mage
范例2:避免同名变量的冲突,local
若函数内定义的变量只在函数内有效,需要定义成本地变量,即使用local定义,只在函数体内或子进程有效。
[root@repo-client scripts]# type local local is a shell builtin [root@repo-client scripts]# help local local: local [option] name[=value] ... Define local variables. Create a local variable called NAME, and give it VALUE. OPTION can be any option accepted by `declare'. Local variables can only be used within a function; they are visible only to the function where they are defined and its children. Exit Status: Returns success unless an invalid option is supplied, an error occurs, or the shell is not executing a function. [root@repo-client scripts]# cat test1 #变量赋值为local test () { local NAME NAME=mage #这两条可以合并为local NAME=mage echo NAME=$NAME } [root@repo-client scripts]# . test1 [root@repo-client scripts]# test NAME=mage [root@repo-client scripts]# NAME=wang [root@repo-client scripts]# echo $NAME wang [root@repo-client scripts]# test #函数内变量 NAME=mage [root@repo-client scripts]# echo $NAME #函数外同名变量,不冲突了 wang
函数的调用方式
-
可在交互式环境下定义函数
-
可将函数放在脚本文件中作为它的一部分
- 可放在只包含函数的单独文件中
调用:函数只有被调用才会执行,通过给定函数名调用函数,函数名出现的地方,会被自动替换为函数代码
函数的生命周期:被调用时创建,返回时终止
#系统自带的函数文件,可以在脚本中直接调用 [root@repo-client scripts]# grep -E -A10 "^(action|success)" /etc/init.d/functions success() { [ "$BOOTUP" != "verbose" -a -z "${LSB:-}" ] && echo_success return 0 } # Log that something failed failure() { local rc=$? [ "$BOOTUP" != "verbose" -a -z "${LSB:-}" ] && echo_failure [ -x /bin/plymouth ] && /bin/plymouth --details return $rc } action() { local STRING rc STRING=$1 echo -n "$STRING " shift "$@" && success $"$STRING" || failure $"$STRING" rc=$? echo return $rc } #action函数里包含了success和failure两个函数,直接调用时,会显示成功和shi'bai [root@repo-client scripts]# . /etc/init.d/functions [root@repo-client scripts]# action "rm -rf /*" rm -rf /* [ OK ] [root@repo-client scripts]# action ldsfe flejlf ldsfe -bash: flejlf: command not found [FAILED]
2.3 函数返回值
1、函数的执行结果返回值:
-
使用echo等命令进行输出
- 函数体中调用命令的输出结果
2、函数的退出状态码:
默认取决于函数中执行的最后一条命令的退出状态码
3、自定义退出状态码,其格式为:
-
return 从函数中返回,用最后状态命令决定返回值
-
return 0 无错误返回
- return 1-255 有错误返回
#1)使用exit退出,返回值100 [root@repo-client scripts]# cat test1 #5)变量赋值 test () { local NAME NAME=mage echo NAME=$NAME exit 100 } [root@repo-client scripts]# cat test1.sh #!/bin/bash #调用test1函数 . test1 test #返回值 echo statue=$? [root@repo-client scripts]# bash test1.sh NAME=mage #只显示NAME,而无statue值,因为调用test1函数后,exit就退出整个脚本了,不会执行echo statue值 #2)使用return退出,返回值也是100 [root@repo-client scripts]# cat test1 #5)变量赋值 test () { local NAME NAME=mage echo NAME=$NAME #exit 100 return 100 } [root@centos7 scripts]# bash test1.sh #执行后,只退出函数,还执行echo statue NAME=mage statue=100
2.4 交互式转化批处理工具 expect
expect 是由Don Libes基于 Tcl( Tool Command Language )语言开发的,主要应用于自动化交互式操作的场景,借助 expect 处理交互的命令,可以将交互过程如:ssh登录,ftp登录等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率。最小化安装系统中没有这个命令,yum安装即可。
expect 语法:
expect [选项] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
常见选项:
-c:从命令行执行expect脚本,默认expect是交互地执行的
-d:可以输出调试信息
示例:
expect -c 'expect "\n" {send "pressed enter\n"}' expect -d ssh.exp [root@centos7 yum.repos.d]# expect -c 'expect "\n" {send "pressed enter\n"}' pressed enter
expect中相关命令
- spawn 启动新的进程
- expect 从进程接收字符串
- send 用于向进程发送字符串
-
interact 允许用户交互
- exp_continue 匹配多个字符串在执行动作后加此命令
expect最常用的语法(tcl语言:模式-动作)
单一分支模式语法:匹配到hi后,会输出“you said hi”,并换行
#捕获hi字符,出现后,打印you said hi [root@centos7 expect]# expect expect1.1> expect "hi" {send "You said hi\n"} halefhiald You said hi expect1.2> exit
多分支模式语法:匹配hi,hello,bye任意字符串时,执行相应输出。不过是一次性的,等同如下
[root@centos8 test]#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> exit [root@centos7 expect]# expect expect1.1> expect { +> "hi" { send "You said hi\n"} +> "hehe" { send "Hehe yourself\n"} +> "bye" { send " Good bye\n"} +> } bye Good bye expect1.2>
范例1:从10.0.0.8主机,非交互式复制fstab文件到7主机的data目录下
[root@centos7 expect]# cat expect1 #!/usr/bin/expect spawn scp /etc/fstab 192.168.100.11:/data expect { "yes/no" { send "yes\n";exp_continue } "password" { send "dongdong\n" } } expect eof [root@centos7 expect]# chmod +x expect1 [root@centos7 expect]# ./expect1 spawn scp /etc/fstab 192.168.100.11:/data The authenticity of host '192.168.100.11 (192.168.100.11)' can't be established. ECDSA key fingerprint is SHA256:LsADkBrAATQSCqxKP9lZXDYm2WncbAvsH3M1Z0ubNpE. ECDSA key fingerprint is MD5:5c:bf:b4:5d:6a:24:38:4e:1c:1e:47:d0:b9:92:c2:08. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.100.11' (ECDSA) to the list of known hosts. root@192.168.100.11's password: fstab 100% 596 126.4KB/s 00:00 [root@c7-test ~]# ll /data/fstab -rw-r--r-- 1 root root 596 Mar 25 21:52 /data/fstab
范例2:自动登录
[root@centos7 expect]# cat expect2 #!/usr/bin/expect spawn ssh 192.168.100.11 expect { "yes/no" { send "yes\n";exp_continue } "password" { send "dongdong\n" } } interact [root@centos7 expect]# chmod +x expect2 [root@centos7 expect]# ./expect2 spawn ssh 192.168.100.11 root@192.168.100.11's password: Last login: Thu Mar 25 21:53:35 2021 from 192.168.100.1 [root@c7-test ~]# exit logout Connection to 192.168.100.11 closed. [root@centos7 expect]#
范例3:定义expect 变量实现非交互式登录
[root@centos7 expect]# cat expect3 #!/usr/bin/expect set ip 192.168.100.11 set user root set password dongdong set timeout 10 spawn ssh $user@$ip expect { "yes/no" { send "yes\n";exp_continue } "password" { send "$password\n" } } interact #测试,删除测试机上的.ssh文件后,执行 [root@c7-test ~]# rm /root/.ssh -rf [root@centos7 expect]# chmod +x expect3 [root@centos7 expect]# ./expect3 spawn ssh root@192.168.100.11 root@192.168.100.11's password: Last login: Thu Mar 25 21:56:36 2021 from 192.168.100.12 [root@c7-test ~]# exit logout Connection to 192.168.100.11 closed. [root@centos7 expect]#
范例4:expect 位置参数,相当于$1 $2等
[root@centos7 expect]# 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@c7-test ~]# rm /root/.ssh -rf [root@centos7 expect]# chmod +x expect4 #命令后加位置参数 [root@centos7 expect]# ./expect4 192.168.100.11 root dongdong spawn ssh root@192.168.100.11 root@192.168.100.11's password: Last login: Thu Mar 25 22:08:21 2021 from 192.168.100.12 [root@c7-test ~]# exit logout Connection to 192.168.100.11 closed. [root@centos7 expect]#
范例5:expect 非交互登录到对方主机,执行多个命令
[root@centos7 expect]# cat expect5 #!/usr/bin/expect set ip [lindex $argv 0] set user [lindex $argv 1] set password [lindex $argv 2] set timeout 10 #非交互登录到对方主机 spawn ssh $user@$ip expect { "yes/no" { send "yes\n";exp_continue } "password" { send "$password\n" } } #创建用户haha,并设置密码 expect "]#" { send "useradd haha\n" } expect "]#" { send "echo $password |passwd --stdin haha\n" } send "exit\n" expect eof [root@centos7 expect]# chmod +x expect5 [root@centos7 expect]# ./expect5 192.168.100.11 root dongdong spawn ssh root@192.168.100.11 root@192.168.100.11's password: Last login: Thu Mar 25 22:11:25 2021 from 192.168.100.12 [root@c7-test ~]# useradd haha [root@c7-test ~]# echo dongdong |passwd --stdin haha Changing password for user haha. passwd: all authentication tokens updated successfully. [root@c7-test ~]# exit logout Connection to 192.168.100.11 closed. [root@centos7 expect]# [root@c7-test ~]# getent passwd|grep haha haha:x:2011:2011::/home/haha:/bin/bash
范例6:shell脚本调用expect,登录到对方主机,并创建用户
[root@centos7 expect]# cat expect6.sh #!/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 $passwordu |passwd --stdin hehe\n" } expect "]#" { send "exit\n" } expect eof EOF [root@centos7 expect]# chmod +x expect6.sh [root@centos7 expect]# ./expect6.sh 192.168.100.11 root dongdong spawn ssh root@192.168.100.11 root@192.168.100.11's password: Last login: Thu Mar 25 22:19:43 2021 from 192.168.100.12 [root@c7-test ~]# useradd hehe [root@c7-test ~]# echo dongdong |passwd --stdin hehe Changing password for user hehe. passwd: all authentication tokens updated successfully. [root@c7-test ~]# exit logout Connection to 192.168.100.11 closed. [root@centos7 expect]# [root@c7-test ~]# getent passwd|grep hehe hehe:x:2012:2012::/home/hehe:/bin/bash
3 数组array
3.1 数组介绍
变量:存储单个元素的内存空间
数组:存储多个元素的连续的内存空间,相当于多个变量的集合
数组名和索引
- 索引的编号从0开始,属于数值索引
- 索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开始支持(centos6之后)
- bash的数组支持稀疏格式(索引不连续)
3.2 声明数组
#普通数组可以不事先声明,直接使用 declare -a ARRAY_NAME #关联数组必须先声明,再使用 declare -A ARRAY_NAME
注意:两者不可相互转换
范例:数组不能相互转换
#关联associative数组和索引index数组不能相互转换 [root@centos7 scripts]# declare -A course [root@centos7 scripts]# declare -a course -bash: declare: course: cannot convert associative to indexed array [root@centos7 scripts]# file=(s*.sh) #定义的是索引数组,不能转换成关联数组 [root@centos7 scripts]# declare -a |grep file declare -a file='([0]="shift_doit.sh" [1]="shift_useradd.sh")' [root@centos7 scripts]# declare -A file -bash: declare: file: cannot convert indexed to associative array
3.3 数组赋值
数组元素的赋值
(1) 一次只赋值一个元素
ARRAY_NAME[INDEX]=VALUE
范例:
weekdays[0]="Sunday" weekdays[4]="Thursday"
范例:单个元素赋值
[root@centos7 ~]# title[0]=ceo [root@centos7 ~]# title[1]=cto [root@centos7 ~]# echo ${title[0]} ceo [root@centos7 ~]# echo ${title[1]} cto [root@centos7 ~]# echo ${title} #不加索引号,就默认第一个 ceo [root@centos7 ~]# declare -a |grep title declare -a title='([0]="ceo" [1]="cto")'
(2) 一次赋值全部元素
ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
范例:
title=("ceo" "coo" "cto") num=({0..10}) alpha=({a..g}) file=( *.sh )
范例:一次赋值全部元素
[root@centos7 ~]# name=(mage wang li zhao) [root@centos7 ~]# declare -a name [root@centos7 ~]# declare -a |grep name declare -a name='([0]="mage" [1]="wang" [2]="li" [3]="zhao")' [root@centos7 ~]# echo ${name[2]} li [root@centos7 ~]# echo ${name[*]} mage wang li zhao #数值 [root@centos7 scripts]# num=({1..10}) [root@centos7 scripts]# declare -a |grep num declare -a num='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="7" [7]="8" [8]="9" [9]="10")' [root@centos7 scripts]# echo ${num[6]} 7 #目录中的文件为元素赋值 [root@centos7 scripts]# ls argsnum.sh dir.sh expect for_99.sh for_continue.sh for_prename.sh guess_number.sh menu.sh shift_doit.sh trap.sh color.sh disk_check.sh file.sh for_break2.sh for_mkdir.sh for_scanhost.sh hostping.sh per.sh shift_useradd.sh createuser.sh excute.sh file.txt for_break.sh for_movedir.sh for_sum.sh init.sh rm_mv.sh trap_exit.sh [root@centos7 scripts]# file=(f*.sh) #把f开头的sh文件当做元素赋值 [root@centos7 scripts]# declare -a |grep file declare -a file='([0]="file.sh" [1]="for_99.sh" [2]="for_break2.sh" [3]="for_break.sh" [4]="for_continue.sh" [5]="for_mkdir.sh" [6]="for_movedir.sh" [7]="for_prename.sh" [8]="for_scanhost.sh" [9]="for_sum.sh")' [root@centos7 scripts]# echo ${file[5]} for_mkdir.sh
(3) 只赋值特定元素
ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
(4) 交互式数组值对赋值
read -a ARRAY
范例:
[root@centos7 scripts]# read -a menu lamian paomo huimian luzhu douzhi [root@centos7 scripts]# echo ${menu[3]} luzhu
3.4 显示所有数组
显示所有数组:
declare -a
范例:
[root@centos7 ~]# declare -a declare -a BASH_ARGC='()' declare -a BASH_ARGV='()' declare -a BASH_LINENO='()' declare -a BASH_SOURCE='()' declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")' declare -a DIRSTACK='()' declare -a FUNCNAME='()' declare -a GROUPS='()' declare -a PIPESTATUS='([0]="0")'
3.5 引用数组
引用数组元素
${ARRAY_NAME[INDEX]} #如果省略[INDEX]表示引用下标为0的元素
范例:
[root@centos7 ~]# declare -a title=([0]="ceo" [1]="coo" [2]="cto") [root@centos7 ~]# echo ${title[1]} coo [root@centos7 ~]# echo ${title} ceo [root@centos7 ~]# echo ${title[2]} cto [root@centos7 ~]# echo ${title[3]} [root@centos7 ~]#
引用数组所有元素
${ARRAY_NAME[*]} ${ARRAY_NAME[@]}
范例:
[root@centos7 ~]# echo ${title[@]} ceo coo cto [root@centos7 ~]# echo ${title[*]} ceo coo cto
数组的长度,即数组中元素的个数
${#ARRAY_NAME[*]} ${#ARRAY_NAME[@]}
范例:
[root@centos7 ~]# echo ${#title[*]} 3 [root@centos7 ~]# alpha=({a..z}) [root@centos7 ~]# echo ${#alpha[@]} 26
3.6 删除数组
删除数组中的某元素,会导致稀疏格式,数组不连续
[root@centos7 ~]# echo ${title[*]} ceo coo cto [root@centos7 ~]# unset title[1] [root@centos7 ~]# echo ${title[*]} ceo cto [root@centos7 ~]# unset alpha[3] [root@centos7 ~]# echo ${#alpha[@]} 25 [root@centos7 ~]# echo ${alpha[2]} c [root@centos7 ~]# echo ${alpha[4]} e [root@centos7 ~]# echo ${alpha[3]} [root@centos7 ~]# echo ${alpha[*]} a b c e f g h i j k l m n o p q r s t u v w x y z
删除整个数组
unset ARRAY
范例:
[root@centos7 ~]# unset title [root@centos7 ~]# echo ${title[*]} [root@centos7 ~]# echo ${#title[*]} 0
3.7 关联数组
declare -A ARRAY_NAME ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2'...)
注意:关联数组必须先声明再调用,下标随意定义。一个数组中可以存放多个变量(key)和值(value)。
范例:未定义关联数组
#如果默认创建关联数组,会当成普通索引数组,下标不合理,会合并成一个下标,即0 [root@centos7 ~]# magedu[ceo]=mage [root@centos7 ~]# declare -a |grep magedu #第一次定义的下标是ceo,但识别出来的只是0 declare -a magedu='([0]="mage")' [root@centos7 ~]# magedu[cto]=wang #第二次定义的下标是cto,也会当做0,所以替换之前的赋值 [root@centos7 ~]# echo ${magedu[ceo]} wang [root@centos7 ~]# declare -a |grep magedu #只保留最后一次的赋值 declare -a magedu='([0]="wang")'
范例:定义关联数组
[root@centos7 ~]# declare -A magedu [root@centos7 ~]# magedu[ceo]=mage [root@centos7 ~]# magedu[cto]=wang [root@centos7 ~]# echo ${magedu[ceo]} mage [root@centos7 ~]# echo ${magedu[cto]} wang [root@centos7 ~]# declare -a |grep magedu [root@centos7 ~]# declare -A |grep magedu declare -A magedu='([ceo]="mage" [cto]="wang" )' [root@centos7 ~]#
范例:定义一个数组多个元素
[root@centos7 ~]# declare -A student [root@centos7 ~]# student[name1]=lijun [root@centos7 ~]# student[name2]=ziqing [root@centos7 ~]# student[age1]=18 [root@centos7 ~]# student[age2]=20 [root@centos7 ~]# student[age2]=16 [root@centos7 ~]# declare -A |grep student declare -A student='([age2]="16" [age1]="18" [name2]="ziqing" [name1]="lijun" )' [root@centos7 ~]# student[gender1]=m [root@centos7 ~]# student[gender2]=f [root@centos7 ~]# student[city1]=nanjing [root@centos7 ~]# student[city2]=beijing [root@centos7 ~]# for i in {1..10};do echo student[name$i]=${student[name$i]}; done student[name1]=lijun student[name2]=ziqing student[name3]= student[name4]= student[name5]= student[name6]= student[name7]= student[name8]= student[name9]= student[name10]= [root@centos7 ~]#
3.8 范例
范例1:生成10个随机数保存于数组中,并找出其最大值和最小值
[root@centos7 scripts]# cat min_max.sh #!/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]} [ ${nums[$i]} -lt $min ] && min=${nums[$i]} done echo "All numbers are ${nums[*]}" echo Max is $max echo Min is $min [root@centos7 scripts]# bash min_max.sh All numbers are 19010 26392 30183 6597 25443 9142 1734 14084 1773 19250 The max numbers is 30183 The min numbers is 1734 [root@centos7 scripts]# bash min_max.sh All numbers are 29778 25987 3225 6644 4313 14984 14970 9396 19655 18413 The max numbers is 29778 The min numbers is 3225
范例2:输入若干个数值存入数组中,采用冒泡算法进行升序或降序排序
[root@centos7 scripts]# bash maopao.sh #!/bin/bash echo "请输入任意数量的数值,空格隔开:" read -a array for((i=0;i<${#array[*]}-1;i++)) do for((j=0;j<${#array[*]}-i-1;j++)) do if [ ${array[j]} -gt ${array[j+1]} ];then temp=${array[j]} array[j]=${array[j+1]} array[j+1]=$temp fi done echo "第`expr $i + 1`次排序结果: ${array[*]}" done echo "排序结果为:${array[*]}" [root@centos7 scripts]# bash maopao.sh 请输入任意数量的数值,空格隔开: 1 5 3 8 0 6 第1次排序结果: 1 3 5 0 6 8 第2次排序结果: 1 3 0 5 6 8 第3次排序结果: 1 0 3 5 6 8 第4次排序结果: 0 1 3 5 6 8 第5次排序结果: 0 1 3 5 6 8 排序结果为:0 1 3 5 6 8 [root@centos7 8000 scripts]# bash maopao.sh 请输入任意数量的数值,空格隔开: 56 129 2 5 -3 12 0 35 第1次排序结果: 56 2 5 -3 12 0 35 129 第2次排序结果: 2 5 -3 12 0 35 56 129 第3次排序结果: 2 -3 5 0 12 35 56 129 第4次排序结果: -3 2 0 5 12 35 56 129 第5次排序结果: -3 0 2 5 12 35 56 129 第6次排序结果: -3 0 2 5 12 35 56 129 第7次排序结果: -3 0 2 5 12 35 56 129 排序结果为:-3 0 2 5 12 35 56 129
- linux(centos)shell脚本编程详解与基本参数、函数等详解
- Shell学习(shell中的函数,数组,告警系统需求分析,告警系统主脚本)-2018.12.27
- shell脚本之正则表达式、函数、grep、sed、awk、printf等基本命令配置详解
- centos shell脚本编程1 正则 shell脚本结构 read命令 date命令的用法 shell中的逻辑判断 if 判断文件、目录属性 shell数组简单用法 $( ) 和${ } 和$(( )) 与 sh -n sh -x sh -v 第三十五节课
- ifconfig命令_Linux ifconfig 命令用法详解:配置和显示Linux系统网卡的网络参数
- linux之基础shell脚本编程3 函数数组
- ubuntu系统下smokping网络监控工具安装配置详解
- 【Linux 系统编程】shell 脚本基础学习之函数(五)
- Shell脚本编程概述(三):函数和数组
- linux网络编程常用函数详解与实例(socket-->bind-->listen-->accept)
- 使用shell脚本采集系统cpu、内存、磁盘、网络等信息
- Linux系统中网络配置详解
- [转] Java网络编程精解之ServerSocket用法详解一
- java网络编程---socket用法详解(学习心得)
- 【Shell 编程基础第二部分】Shell里的流程控制、Shell里的函数及脚本调试方法!
- linux网络编程常用函数详解与实例
- 【Shell 编程基础第二部分】Shell里的流程控制、Shell里的函数及脚本调试方法!
- Java网络编程精解之ServerSocket用法详解二2
- Shell脚本编程——了解你的Linux系统必须掌握的20个命令
- vmware ubuntu系统配置,网络配置