一、网络管理
1.1 常见的网络配置命令,主机上网配置
1.1.1 主机上网配置
在Rocky系统中(前centOS),主机上网主要在 /etc/sysconfig/network-scripts 目录下对网卡文件进行相应配置,ip地址有静态指定和动态分配两种方式。
静态指定:
TYPE=Ethernet # 类型
BOOTPROTO=none # ip分配方式,none|static静态,dhcp动态
NAME=ens224 # 命令行下的网卡名
DEVICE=ens224 # 网卡设备名
IPADDR=192.168.244.100 # ip地址
NETMASK=255.255.255.0 # 子网掩码
GATEWAY=192.168.244.1 # 网关
PREFIX=24 # 前缀
ONBOOT=yes # 开机自启
DNS1=114.114.114.114 # DNS1
DNS2=223.5.5.5 # DNS2
动态指定:
TYPE=Ethernet # 类型
BOOTPROTO=dhcp # ip分配方式,none|static静态,dhcp动态
NAME=ens224 # 命令行下的网卡名
DEVICE=ens224 # 网卡设备名
ONBOOT=yes # 开机自启
接着使用nmcli命令重启下网卡配置即可
1.1.2 网络配置命令
在使用网络配置命令前先安装net-tool工具包:
yum -y install net-tool
主机名
主机名可通过hostname命令查看
# 主机名
[root@rocky etc]# hostname
rocky
# 通过主机名dns反解得到的ip地址
[root@rocky etc]# hostname -i
192.168.206.133
# 显示所有IP地址
[root@rocky etc]# hostname -I
192.168.206.133 192.168.122.1
# 修改主机名(临时生效)
[root@rocky etc]# hostname hello
[root@rocky etc]# hostname
hello
注意:通过hostname修改的主机名临时生效,想要永久生效需要通过hostnamectl命令
hostnamectl修改主机名永久生效
# 修改hostname
[root@rocky etc]# hostnamectl set-hostname hello
# 查看已修改
[root@rocky etc]# hostnamectl
Static hostname: hello
Icon name: computer-vm
Chassis: vm
Machine ID: 81b007fa45f740bf89bfe92c1dfeca15
Boot ID: 38aef8d9d09943178c7c1dc54dde6461
Virtualization: vmware
Operating System: Rocky Linux 8.6 (Green Obsidian)
CPE OS Name: cpe:/o:rocky:rocky:8:GA
Kernel: Linux 4.18.0-372.9.1.el8.x86_64
Architecture: x86-64
ifconfig
ifconfig命令主要用于网卡设备的配置。
常用命令用法:
ifconfig # 查看所有网卡设备
-a # 显示所有(包括未up的设备)
# -s 显示网络流量统计信息
[root@rocky etc]# ifconfig -s
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
ens160 1500 140501 0 0 0 19384 0 0 0 BMRU
lo 65536 48 0 0 0 48 0 0 0 LRU
virbr0 1500 0 0 0 0 0 0 0 0 BMU
# 修改网卡ip,临时有效
ifconfig ens160 192.168.206.140 netmask 255.255.255.0
ifconfig ens160 # 查看指定设备
ifconfig ens160 down # 禁用
ifconfig ens160 up # 启用
route
route是路由管理命令,建议使用ip代替。
[root@rocky etc]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.206.2 0.0.0.0 UG 100 0 0 ens160
192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
192.168.206.0 0.0.0.0 255.255.255.0 U 100 0 0 ens160
# 使用 ip 地址显示
[root@rocky etc]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.206.2 0.0.0.0 UG 100 0 0 ens160
192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
192.168.206.0 0.0.0.0 255.255.255.0 U 100 0 0 ens160
# 查看Ipv6路由
[root@rocky etc]# route -6n
Kernel IPv6 routing table
Destination Next Hop Flag Met Ref Use If
::1/128 :: U 256 1 0 lo
fe80::/64 :: U 1024 1 0 ens160
::/0 :: !n -1 1 0 lo
::1/128 :: Un 0 4 0 lo
fe80::20c:29ff:fe49:af89/128 :: Un 0 4 0 ens160
ff00::/8 :: U 256 3 0 ens160
::/0 :: !n -1 1 0 lo
route添加和删除路由的命令不作介绍,建议使用ip route命令管理路由:
# 添加路由
[root@rocky etc]# ip route add 172.16.0.145 dev ens160 via 192.168.206.133
# 显示路由
[root@rocky etc]# ip route show
default via 192.168.206.2 dev ens160 proto dhcp metric 100
172.16.0.145 via 192.168.206.133 dev ens160
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown
192.168.206.0/24 dev ens160 proto kernel scope link src 192.168.206.133 metric 100
# 删除路由
[root@rocky etc]# ip route del 172.16.0.145 dev ens160 via 192.168.206.133
[root@rocky etc]# ip route show
default via 192.168.206.2 dev ens160 proto dhcp metric 100
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown
192.168.206.0/24 dev ens160 proto kernel scope link src 192.168.206.133 metric 100
netstat
网络套接字管理命令,建议使用ss代替,此处不作介绍,详细用法与ss类似。
流量统计数据
[root@rocky etc]# cat /proc/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 4080 48 0 0 0 0 0 0 4080 48 0 0 0 0 0 0
ens160: 95144854 140972 0 0 0 0 0 69055 1285418 19682 0 0 0 0 0 0
virbr0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[root@rocky etc]# ifconfig -s
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
ens160 1500 140998 0 0 0 19697 0 0 0 BMRU
lo 65536 48 0 0 0 48 0 0 0 LRU
virbr0 1500 0 0 0 0 0 0 0 0 BMU
[root@rocky etc]# netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
ens160 1500 141119 0 0 0 19844 0 0 0 BMRU
lo 65536 48 0 0 0 48 0 0 0 LRU
virbr0 1500 0 0 0 0 0 0 0 0 BMU
ip
ip命令,可以代替ifconfig和route。
配置linux网络属性:
# 显示网卡信息
[root@rocky etc]# ip address show ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:49:af:89 brd ff:ff:ff:ff:ff:ff
inet 192.168.206.133/24 brd 192.168.206.255 scope global dynamic noprefixroute ens160
valid_lft 1029sec preferred_lft 1029sec
inet6 fe80::20c:29ff:fe49:af89/64 scope link noprefixroute
valid_lft forever preferred_lft forever
# 禁用
ip address set ens160 down
# 改名
ip address set ens160 name ens160-test
# 启用
ip address set ens160-test up
# 查看网卡链路层信息
[root@rocky etc]# ip link show ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:49:af:89 brd ff:ff:ff:ff:ff:ff
# 添加ip信息
[root@rocky etc]# ip address add 192.168.207.110/24 dev ens160
# 查看
[root@rocky etc]# ip a s ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:49:af:89 brd ff:ff:ff:ff:ff:ff
inet 192.168.206.133/24 brd 192.168.206.255 scope global dynamic noprefixroute ens160
valid_lft 1406sec preferred_lft 1406sec
inet 192.168.207.110/24 scope global ens160
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe49:af89/64 scope link noprefixroute
valid_lft forever preferred_lft forever
# 删除ip信息
[root@rocky etc]# ip address del 192.168.207.110/24 dev ens160
# 查看
[root@rocky etc]# ip a s ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:49:af:89 brd ff:ff:ff:ff:ff:ff
inet 192.168.206.133/24 brd 192.168.206.255 scope global dynamic noprefixroute ens160
valid_lft 1343sec preferred_lft 1343sec
inet6 fe80::20c:29ff:fe49:af89/64 scope link noprefixroute
valid_lft forever preferred_lft forever
# 添加网卡别名
[root@rocky etc]# ip address add 192.168.206.150/24 dev ens160 label ens160:148
# 查看
[root@rocky etc]# ifconfig ens160
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.206.133 netmask 255.255.255.0 broadcast 192.168.206.255
inet6 fe80::20c:29ff:fe49:af89 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:49:af:89 txqueuelen 1000 (Ethernet)
RX packets 144101 bytes 95409334 (90.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 21899 bytes 1862688 (1.7 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@rocky etc]# ifconfig ens160:148
ens160:148: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.206.150 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:0c:29:49:af:89 txqueuelen 1000 (Ethernet)
[root@rocky etc]# ip a s ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:49:af:89 brd ff:ff:ff:ff:ff:ff
inet 192.168.206.133/24 brd 192.168.206.255 scope global dynamic noprefixroute ens160
valid_lft 1081sec preferred_lft 1081sec
inet 192.168.206.150/24 scope global secondary ens160:148
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe49:af89/64 scope link noprefixroute
valid_lft forever preferred_lft forever
# 删除网卡别名
[root@rocky etc]# ip address del 192.168.206.150/24 dev ens160 label ens160:148
[root@rocky etc]# ip a s ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:49:af:89 brd ff:ff:ff:ff:ff:ff
inet 192.168.206.133/24 brd 192.168.206.255 scope global dynamic noprefixroute ens160
valid_lft 990sec preferred_lft 990sec
inet6 fe80::20c:29ff:fe49:af89/64 scope link noprefixroute
valid_lft forever preferred_lft forever
ip route路由管理命令在route已作介绍。
ss
ss与netstat命令类似,是网络socket管理命令。常用选项如下:
-n # 不以主机名显示
-p # 显示进程信息
-a # 显示所有
-l # 显示listen状态的
-s # 显示统计信息
-4 # 仅显示ipv4
-6 # 仅显示ipv6
-t # 仅显示tcp
-u # 仅显示udp
-e # 仅显示establish状态的
# 用法示例:以ip地址形式显示所有listen状态的tcp套接字,含对应进程
[root@rocky ~]# ss -tnlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=995,fd=4),("systemd",pid=1,fd=31))
LISTEN 0 32 192.168.122.1:53 0.0.0.0:* users:(("dnsmasq",pid=1971,fd=6))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1085,fd=4))
LISTEN 0 5 127.0.0.1:631 0.0.0.0:* users:(("cupsd",pid=1107,fd=10))
LISTEN 0 128 [::]:111 [::]:* users:(("rpcbind",pid=995,fd=6),("systemd",pid=1,fd=35))
LISTEN 0 128 *:80 *:* users:(("httpd",pid=2214,fd=4),("httpd",pid=2213,fd=4),("httpd",pid=2212,fd=4),("httpd",pid=1125,fd=4))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1085,fd=6))
LISTEN 0 5 [::1]:631 [::]:* users:(("cupsd",pid=1107,fd=9))
nmcli
nmcli是常用的网络管理命令,用于启用禁用网络设备等。
# 网卡连接状态
[root@rocky ~]# nmcli connection show
NAME UUID TYPE DEVICE
ens160 e538e7ba-2349-4c39-a784-fdff3c82253e ethernet ens160
virbr0 d58fac34-33ce-4b5b-a60e-0269038834cc bridge virbr0
# 显示网卡连接信息
[root@rocky ~]# nmcli connection show ens160
...
# 显示网卡状态
[root@rocky ~]# nmcli dev status
DEVICE TYPE STATE CONNECTION
ens160 ethernet connected ens160
virbr0 bridge connected (externally) virbr0
lo loopback unmanaged --
# 显示网卡信息
[root@rocky ~]# nmcli dev show ens160
GENERAL.DEVICE: ens160
GENERAL.TYPE: ethernet
GENERAL.HWADDR: 00:0C:29:49:AF:89
GENERAL.MTU: 1500
GENERAL.STATE: 100 (connected)
GENERAL.CONNECTION: ens160
GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/1
WIRED-PROPERTIES.CARRIER: on
IP4.ADDRESS[1]: 192.168.206.133/24
IP4.GATEWAY: 192.168.206.2
IP4.ROUTE[1]: dst = 192.168.206.0/24, nh = 0.0.0.0, mt = 100
IP4.ROUTE[2]: dst = 0.0.0.0/0, nh = 192.168.206.2, mt = 100
IP4.DNS[1]: 192.168.206.2
IP4.DOMAIN[1]: localdomain
IP6.ADDRESS[1]: fe80::20c:29ff:fe49:af89/64
IP6.GATEWAY: --
IP6.ROUTE[1]: dst = fe80::/64, nh = ::, mt = 1024
# 删除链接
nmcli con del ens160
# 禁用
nmcli con down ens160
# 启用
nmcli con up ens160
# 配置重新生效
nmcli con reload
1.2 /etc/sysconfig/network-scripts/ifcfg-eth0配置格式
以ens160为例,说明文件/etc/sysconfig/network-scripts/ifcfg-eth0的配置格式
[root@rocky ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens160
TYPE=Ethernet # 类型
PROXY_METHOD=none # 设备名
BROWSER_ONLY=no # 指定是否仅限浏览器使用代理
BOOTPROTO=dhcp # ip分配方式
DEFROUTE=yes # 默认路由开启
IPV4_FAILURE_FATAL=no # 在 IPv4 连接失败时是否认为是致命错误。
NAME=ens160 # 设备命令行显示
UUID=e538e7ba-2349-4c39-a784-fdff3c82253e # 设备唯一标识
DEVICE=ens160 # 设备名
ONBOOT=yes # 开机自启
1.3 bond0的配置实现
将多块网卡绑定同一IP地址对外提供服务,可以实现高可用或者负载均衡。直接给两块网卡设置同一IP地址是不可以的。通过 bonding,虚拟一块网卡对外提供连接,物理网卡的被修改为相同MAC地址。
以下介绍bond0的配置实现
先添加2块仅主机模式的网卡(ens192, ens224):
[root@rocky ~]# ip a s
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: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:49:af:89 brd ff:ff:ff:ff:ff:ff
inet 192.168.206.133/24 brd 192.168.206.255 scope global dynamic noprefixroute ens160
valid_lft 1768sec preferred_lft 1768sec
inet6 fe80::20c:29ff:fe49:af89/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:49:af:93 brd ff:ff:ff:ff:ff:ff
4: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:49:af:9d brd ff:ff:ff:ff:ff:ff
5: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:74:aa:a4 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
编辑网卡配置
[root@rocky network-scripts]# vim ifcfg-bond0
NAME=bond0
TYPE=bond
DEVICE=bond0
BOOTPROTO=none
IPADDR=192.168.10.100
PREFIX=24
BONDING_OPTS="mode=1 miimon=100 fail_over_mac=1" #工作模式为主备,心跳建策时间间隔为100ms
[root@rocky network-scripts]# vim ifcfg-ens192
NAME=ens192
DEVICE=ens192
BOOTPROTO=none
MASTER=bond0
SLAVE=yes
ONBOOT=yes
[root@rocky network-scripts]# vim ifcfg-ens224
NAME=ens224
DEVICE=ens224
BOOTPROTO=none
MASTER=bond0
SLAVE=yes
ONBOOT=yes
nmcli重载配置,查看网卡连接状态
[root@rocky network-scripts]# nmcli con reload
[root@rocky network-scripts]# nmcli con show
NAME UUID TYPE DEVICE
ens160 e538e7ba-2349-4c39-a784-fdff3c82253e ethernet ens160
bond0 ad33d8b0-1f7b-cab9-9447-ba07f855b143 bond bond0
virbr0 39357c55-b7fc-453f-bb68-2558e28e600e bridge virbr0
ens192 03da7500-2101-c722-2438-d0d006c28c73 ethernet ens192
ens224 e4014630-448b-5ad3-4992-f4678202147c ethernet ens224
[root@rocky network-scripts]# ip a s | grep bond0
3: ens192: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP group default qlen 1000
4: ens224: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP group default qlen 1000
6: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
inet 192.168.10.100/24 brd 192.168.10.255 scope global noprefixroute bond0
# 查看bond状态,当前活跃的网卡是ens192
[root@rocky network-scripts]# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)
Bonding Mode: fault-tolerance (active-backup) (fail_over_mac active)
Primary Slave: None
Currently Active Slave: ens192 # 当前活跃网卡
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
Peer Notification Delay (ms): 0
Slave Interface: ens192
MII Status: up
Speed: 10000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:0c:29:49:af:93
Slave queue ID: 0
Slave Interface: ens224
MII Status: up
Speed: 10000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:0c:29:49:af:9d
Slave queue ID: 0
ping测试
[root@rocky ~]# ping -c 1 192.168.206.133
PING 192.168.206.133 (192.168.206.133) 56(84) bytes of data.
64 bytes from 192.168.206.133: icmp_seq=1 ttl=64 time=0.226 ms
--- 192.168.206.133 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.226/0.226/0.226/0.000 ms
断掉网卡ens192,活跃网卡变成ens224
[root@rocky network-scripts]# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)
Bonding Mode: fault-tolerance (active-backup) (fail_over_mac active)
Primary Slave: None
Currently Active Slave: ens224 # 活跃网卡发生的变化
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
Peer Notification Delay (ms): 0
Slave Interface: ens192
MII Status: down
Speed: Unknown
Duplex: Unknown
Link Failure Count: 1
Permanent HW addr: 00:0c:29:49:af:93
Slave queue ID: 0
Slave Interface: ens224
MII Status: up
Speed: 10000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:0c:29:49:af:9d
Slave queue ID: 0
重新连接网卡ens192,bond0信息不变,避免频繁切换影响网络状态稳定性。
删除bond0:
[root@rocky network-scripts]# nmcli con down bond0
Connection 'bond0' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/5)
[root@rocky network-scripts]# nmcli con show
NAME UUID TYPE DEVICE
ens160 e538e7ba-2349-4c39-a784-fdff3c82253e ethernet ens160
virbr0 39357c55-b7fc-453f-bb68-2558e28e600e bridge virbr0
bond0 ad33d8b0-1f7b-cab9-9447-ba07f855b143 bond --
ens192 03da7500-2101-c722-2438-d0d006c28c73 ethernet --
ens224 e4014630-448b-5ad3-4992-f4678202147c ethernet --
[root@rocky network-scripts]# rm -f ifcfg-{bond0,ens192,ens224}
[root@rocky network-scripts]# ls
ifcfg-ens160
[root@rocky network-scripts]# nmcli con reload
[root@rocky network-scripts]# nmcli con
NAME UUID TYPE DEVICE
ens160 e538e7ba-2349-4c39-a784-fdff3c82253e ethernet ens160
virbr0 39357c55-b7fc-453f-bb68-2558e28e600e bridge virbr0
1.4 基于ifconfig命令结果找到ip地址
二、shell编程进阶
2.1 ifconfig命令获取网卡ip
# 使用 grep 命令
[root@rocky network-scripts]# ifconfig ens160 | grep netmask | grep -oE "([0-9]+\.){3}[0-9]+"| head -n1
192.168.206.133
# 使用 sed 命令
[root@rocky network-scripts]# ifconfig ens160 | sed -En '/netmask/s/[^0-9]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/\1/p'
192.168.206.133
2.2 使用脚本判断 你主机所在网络内在线的主机IP有哪些? ping通则在线
[root@rocky network-scripts]# for i in `seq 1 254`; do ping -c1 -W0.001 192.168.206.${i} > /dev/null && echo "connect 192.168.206.${i} ok"; done
2.3 通过/etc/passwd,计算用户id总和
方法一:不使用while循环
[root@rocky dir1]# cut -s -d: -f3 /etc/passwd | paste -sd+ | bc
85682
方法二:使用while循环read
[root@rocky dir1]# vim 1.sh
#!/bin/bash
sum=0
while read line
do
number=`echo ${line} | cut -d: -f3`
let sum=${sum}+${number}
done < /etc/passwd
echo ${sum}
[root@rocky dir1]# bash 1.sh
85682
2.4 数组
2.4.1 索引数组
索引数组是下标从0开始依次编号的数组。
声明数组:
[root@rocky dir1]# declare -a myArray
数组赋值
# 一个一个赋值
[root@rocky dir1]# myArray[0]="cat"
[root@rocky dir1]# myArray[2]="dog"
# 一次赋值
[root@rocky dir1]# fruits=("apple" "banana" "peach")
[root@rocky dir1]# numbers=({0..9})
[root@rocky dir1]# file=(*.sh)
# 只赋值特定元素
[root@rocky dir1]# myArray=([0]="chicken" [3]="cow")
引用元素
# 引用单个
[root@rocky dir1]# echo ${myArray[0]}
chicken
[root@rocky dir1]# echo ${myArray}
chicken
[root@rocky dir1]# echo ${myArray[3]}
cow
# 引用所有
[root@rocky dir1]# echo ${myArray[@]}
chicken cow
[root@rocky dir1]# echo ${myArray[*]}
chicken cow
[root@rocky dir1]# echo ${fruits[*]}
apple banana peach
#数组长度
[root@rocky dir1]# echo ${#fruits[*]}
3
#数组下标(用于遍历)
[root@rocky dir1]# echo ${!fruits[*]}
0 1 2
删除数组
删除单个元素
[root@rocky dir1]# echo ${fruits[*]}
apple banana peach
[root@rocky dir1]# unset fruits[1]
[root@rocky dir1]# echo ${fruits[*]}
apple peach
删除整个数组
[root@rocky dir1]# unset fruits
[root@rocky dir1]# echo ${fruits[*]}
[root@rocky dir1]#
数组数据处理
数组切片:
[root@rocky dir1]# echo ${numbers[*]}
0 1 2 3 4 5 6 7 8 9
# 从第三个元素起去3个元素
[root@rocky dir1]# echo ${numbers[*]:3:3}
3 4 5
# 从第5个元素取至最后
[root@rocky dir1]# echo ${numbers[*]:5}
5 6 7 8 9
向数组追加元素:
[root@rocky dir1]# echo ${#numbers[*]}
10
[root@rocky dir1]# numbers[${#numbers[*]}]=11
[root@rocky dir1]# echo ${numbers[*]}
0 1 2 3 4 5 6 7 8 9 11
2.4.2 关联数组
关联数组可以自定义下标,相当于python里面的字典。需要优先声明,才能使用。
主要用法:
# 声明
[root@rocky dir1]# declare -A students
# 赋值
[root@rocky dir1]# students["zhangsan"]=89
[root@rocky dir1]# students["lisi"]=92
[root@rocky dir1]# students["wangwu"]=84
# 取值
[root@rocky dir1]# echo ${students[*]}
92 89 84
# 取特定值
[root@rocky dir1]# echo ${students[zhangsan]}
89
# 取下标
[root@rocky dir1]# echo ${!students[@]}
lisi zhangsan wangwu
2.5 字符串
字符串取长度和切片
[root@rocky dir1]# var="abcd1234"
# 长度
[root@rocky dir1]# echo ${#var}
8
# 切片
[root@rocky dir1]# echo ${var:2}
cd1234
[root@rocky dir1]# echo ${var:2:5}
cd123
[root@rocky dir1]# echo ${var: -4}
1234
[root@rocky dir1]# echo ${var:1:-4}
bcd
[root@rocky dir1]# echo ${var: -6:-4}
cd
根据子串切割字符串
删左边:
[root@rocky dir1]# var="abcd1234abcd1234"
# 删除第一个cd及左边内容
[root@rocky dir1]# echo ${var#*cd}
1234abcd1234
# 删除开头的ab
[root@rocky dir1]# echo ${var#ab}
cd1234abcd1234
# 删除最后一个cd及左边内容(贪婪匹配)
[root@rocky dir1]# echo ${var##*cd}
1234
删右边:
[root@rocky dir1]# echo ${var%cd*}
abcd1234ab
[root@rocky dir1]# echo ${var%%cd*}
ab
[root@rocky dir1]# echo ${var%%1234}
abcd1234abcd
替换字符串
[root@rocky dir1]# var="abcd1234abcd12345"
# 替换第一个123
[root@rocky dir1]# echo ${var/123/XYZ}
abcdXYZ4abcd12345
# 替换所有123
[root@rocky dir1]# echo ${var//123/XYZ}
abcdXYZ4abcdXYZ45
# 替换开头的abc
[root@rocky dir1]# echo ${var/#abc/XYZ}
XYZd1234abcd12345
# 替换结尾的2345
[root@rocky dir1]# echo ${var/%2345/XYZ}
abcd1234abcd1XYZ
删除字符串
[root@rocky dir1]# var="abcd1234abcd12345"
# 删除第一个123
[root@rocky dir1]# echo ${var/123}
abcd4abcd12345
# 删除全部123
[root@rocky dir1]# echo ${var//123}
abcd4abcd45
# 删除开头abc
[root@rocky dir1]# echo ${var/#abc}
d1234abcd12345
# 删除结尾2345
[root@rocky dir1]# echo ${var/%2345}
abcd1234abcd1
大小写转化
[root@rocky dir1]# var="abcd1234ABCD12345"
[root@rocky dir1]# echo ${var^^}
ABCD1234ABCD12345
[root@rocky dir1]# echo ${var,,}
abcd1234abcd12345
模糊匹配变量名
[root@rocky dir1]# a1=10;a2=20;a3=30
[root@rocky dir1]# echo ${!a*}
a1 a2 a3
2.6 高级变量
2.6.1 高级变量赋值
高级变量赋值可以简化shell编程的if..else..操作。
[root@rocky dir1]# var=ab
[root@rocky dir1]# echo ${var-xy}
ab
[root@rocky dir1]# var=""
[root@rocky dir1]# echo ${var-xy}
[root@rocky dir1]# unset var
[root@rocky dir1]# echo ${var-xy}
xy
[root@rocky dir1]# echo ${var:-xy}
ab
[root@rocky dir1]# echo ${var:-xy}^C
[root@rocky dir1]# var=""
[root@rocky dir1]# echo ${var:-xy}
xy
[root@rocky dir1]# unset var
[root@rocky dir1]# echo ${var:-xy}
xy
2.6.2 有类型变量
可以通过declare命令的选项声明变量类型。
-f #显示已定义所有函数名及内容
-F #显示已定义所有函数名
-p #显示每个变量属性和值
-a #声明定义为为数组的变量
-A #声明定义为关联数组的变量
-i #声明或显示定义为整型的变量
-l #声明或显示定义为小写的变量
-n #变量引用另外一个变量的值
-r #声明或显示只读变量
-t #声明或显示具有trace属性的变量
-u #声明或显示定义为大写的变量
-x #显示环境变量和函数,相当于export
2.6.3 eval
eval命令会现将变量进行置换,然后执行命令。
[root@rocky dir1]# CMD="ip a s ens160"
[root@rocky dir1]# echo ${CMD}
ip a s ens160
[root@rocky dir1]# eval ${CMD}
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:49:af:89 brd ff:ff:ff:ff:ff:ff
inet 192.168.206.133/24 brd 192.168.206.255 scope global dynamic noprefixroute ens160
valid_lft 1116sec preferred_lft 1116sec
inet6 fe80::20c:29ff:fe49:af89/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[root@rocky dir1]# ty=e
[root@rocky dir1]# echo {a..$ty}
{a..e}
[root@rocky dir1]# eval echo {a..$ty}
a b c d e
2.6.4 间接变量引用
[root@rocky dir1]# v1=v2
[root@rocky dir1]# v2=v3
[root@rocky dir1]# echo $v1
v2
[root@rocky dir1]# echo \$$v1
$v2
# 两种间接变量引用的方法
[root@rocky dir1]# eval echo \$$v1
v3
[root@rocky dir1]# echo ${!v1}
v3
2.7 求10个随机数的最大值与最小值
#!/bin/bash
max() {
max=0
for num in $@
do
[ ${num} -gt ${max} ] && max=$num
done
echo $max
}
min() {
min=32767
for num in $@
do
[ ${num} -lt ${min} ] && min=$num
done
echo $min
}
for i in {0..9}
do
numbers[i]=$RANDOM
done
max ${numbers[@]}
min ${numbers[@]}
2.8 使用递归调用,完成阶乘算法实现
[root@rocky dir1]# vim fac2.sh
#!/bin/bash
fac(){
if [ $1 -gt 1 ];then
echo $[$1 * $(fac $[$1-1])]
else
echo 1
fi
}
fac $1
[root@rocky dir1]# bash fac2.sh 5
120
[root@rocky dir1]# bash fac2.sh 7
5040
三、进程管理与定时任务
3.1 进程与线程的区别
- 进程是操作系统分配资源的最小单位,线程是程序执行的CPU调度的最小单位;
- 一个进程有一个或多个线程组成,线程是一个进程中代码的不同执行路线;
- 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间及一些进程的资源,某进程内的线程在其它进程不可见;
- 线程上下文切换比进程上下文切换要快得多。
3.2 进程的结构
内核中的每一个进程信息由进程控制块PCB记录,所有PCB连接成一个双向循环链表。其中PCB包含的信息如下:
- 进程id、用户id和组id
- 程序计数器
- 进程的状态
- 进程切换时需要保护和恢复的CPU寄存器的值
- 描述虚拟地址空间的信息
- 描述控制终端的信息
- 当前工作目录
- 文件描述符表,包含很多指向file结构体的指针
- 进程可以使用的资源上限
- 输入输出状态:配置进程使用的I/O设备。
3.3 进程的状态
进程的基本状态有以下几种:
- 创建状态:进程在创建时需要申请一个空白PCB(process control block进程控制块),向其中填写控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态
- 就绪状态:进程已准备好,已分配到所需资源,只要分配到CPU就能够立即运行
- 执行状态:进程处于就绪状态被调度后,进程进入执行状态;
- 阻塞状态:正在执行的进程由于某些时间而暂时无法运行,进程收到阻塞,在满足请求时进入就绪状态等待系统调用;
- 终止状态:进程结束,或出现错误,或被系统终止,进入终止状态,无法再执行。
可以通过ps aux命令的STAT列查看进程的状态:
僵尸进程:
Linux系统下有一种进程状态叫僵尸态(Zombie)。当父进程处于Stop停止状态时,其子进程被杀死后,由于父进程无法被调度,无法回收子进程的PCB等资源,此时子进程就成为了僵尸进程。当有大量的僵尸进程时会占用大量的系统资源,带来不小的危害。
手动制造僵尸进程:
# 在一个窗口开启一个父进程
[root@rocky dir1]# tail -f /var/log/messages
# 在另一个窗口执行操作,查看进程树
[root@rocky ~]# pstree -p | grep tail
|-sshd(1087)-+-sshd(2453)---sshd(2479)---bash(2489)---tail(3444)
# 父子进程都处于睡眠状态
[root@rocky ~]# ps aux | grep 3444
root 3444 0.0 0.0 217116 872 pts/0 S+ 16:32 0:00 tail -f /var/log/messages
root 3456 0.0 0.0 221936 1184 pts/1 S+ 16:33 0:00 grep --color=auto 3444
[root@rocky ~]# ps aux | grep 2489
root 2489 0.0 0.3 237620 5688 pts/0 Ss 15:18 0:00 -bash
root 3458 0.0 0.0 221936 1184 pts/1 S+ 16:33 0:00 grep --color=auto 2489
# 父进程进入停止状态
[root@rocky ~]# kill -19 2489
[root@rocky ~]# ps aux | grep 2489
root 2489 0.0 0.3 237620 5688 pts/0 Ts 15:18 0:00 -bash
root 3460 0.0 0.0 221936 1184 pts/1 S+ 16:33 0:00 grep --color=auto 2489
[root@rocky ~]# ps aux | grep 3444
root 3444 0.0 0.0 217116 872 pts/0 S+ 16:32 0:00 tail -f /var/log/messages
root 3462 0.0 0.0 221936 1096 pts/1 S+ 16:33 0:00 grep --color=auto 3444
# 杀死子进程,子进程进入僵尸态
[root@rocky ~]# kill 3444
[root@rocky ~]# ps aux | grep 3444
root 3444 0.0 0.0 0 0 pts/0 Z+ 16:32 0:00 [tail] <defunct>
root 3472 0.0 0.0 221936 1076 pts/1 S+ 16:34 0:00 grep --color=auto 3444
# 唤醒父进程,随后子进程被回收,父进程恢复睡眠态
[root@rocky ~]# kill -18 2489
[root@rocky ~]# ps aux | grep 3444
root 3474 0.0 0.0 221936 1168 pts/1 S+ 16:35 0:00 grep --color=auto 3444
[root@rocky ~]# ps aux | grep 2489
root 2489 0.0 0.3 237620 5688 pts/0 Ss+ 15:18 0:00 -bash
root 3484 0.0 0.0 221936 1088 pts/1 S+ 16:35 0:00 grep --color=auto 2489
孤儿进程:
在子进程退出前, 父进程先退出,此时子进程成为孤儿进程,被systemd进程接管。孤儿进程依然在运行中,只是父进程发生了变化。
# 在一个窗口开启一个screen, ping baidu
[root@rocky ~]# screen -S test
[root@rocky ~]# ping www.baidu.com
# ping进程树
[root@rocky ~]# pstree -p | grep ping
|-sshd(1087)-+-sshd(2453)---sshd(2479)---bash(2489)---screen(3563)---screen(3564)---bash(3565)---ping(3591)
# 关闭screen窗口后,screen进程被systemd接管,成为孤儿进程
[root@rocky ~]# pstree -p | grep ping
|-screen(3564)---bash(3565)---ping(3591)
[root@rocky ~]# pstree -sp 3591
systemd(1)───screen(3564)───bash(3565)───ping(3591)
3.4 进程通信
IPC: Inter Process Communication,同一主机通信。通信方式:
pipe #管道,单向传输
socket #套接字文件,双工通信
Memory-maped file #文件映射,将文件中的一段数据映射到物理内存,多个进程共享这片内存
shm shared memory #共享内存
signal #信号
Lock #对资源上锁,如果资源已被某进程锁住,则其它进程想使用这些资源,都将被阻塞,直到锁被打开
semaphore #信号量,一种计数器
RPC: Remote Process Communication,不同主机通信,通信方式主要通过消息队列:rabbitMQ, RocketMQ, Kafka
3.5 前台与后台
前台作业:通过终端启动,但一直占用终端。
后台作业:可通过终端启动运行,不占用终端。
创建后台进程:
[root@rocky dir1]# vim a.sh
#!/bin/bash
while :;
do
echo "haha"
sleep 1
done
# 按ctrl+Z进入后台运行,状态为stop
[root@rocky dir1]# bash a.sh
haha
haha
^Z
[1]+ Stopped bash a.sh
# 末尾加&直接在后台运行,状态running
[root@rocky dir1]# sleep 1000 &
[2] 4559
# 查看后台进程
[root@rocky dir1]# jobs
[1]+ Stopped bash a.sh
[2]- Running sleep 1000 &
# ps可看到后台进程
[root@rocky dir1]# ps aux
root 4559 0.0 0.0 217080 860 pts/0 S 18:05 0:00 sleep 1000
root 4577 0.0 0.0 217080 908 ? S 18:07 0:00 sleep 60
root 4578 0.0 0.2 268548 4040 pts/0 R+ 18:07 0:00 ps aux
后台作业控制:
[root@rocky dir1]# jobs
[1]+ Stopped bash a.sh
[2]- Running sleep 1000 &
# 将作业放入前台运行
[root@rocky dir1]# fg 1
bash a.sh
haha
haha
haha
haha
[root@rocky dir1]# jobs
[1]+ Stopped bash a.sh
[2]- Running sleep 1000 &
# 将后台作业继续在后台运行
[root@rocky dir1]# bg 1
[1]+ bash a.sh &
[root@rocky dir1]# haha
haha
haha
haha
# 均是running状态
[root@rocky dir1]# jobhaha
s
[1]- Running bash a.sh &
[2]+ Running sleep 1000 &
# 杀死后台进程
[root@rocky dir1]# kill %1^C
[1]- Terminated bash a.sh
[root@rocky dir1]# jobs
[2]+ Running sleep 1000 &
[root@rocky dir1]# ps aux | grep " a.sh"
root 4857 0.0 0.0 221936 1180 pts/0 S+ 18:13 0:00 grep --color=auto a.sh
kill命令控制后台进程
[root@rocky dir1]# jobs
[2]+ Running sleep 1000 &
[root@rocky dir1]# ps aux | grep "sleep 1000"
root 4559 0.0 0.0 217080 860 pts/0 S 18:05 0:00 sleep 1000
root 4867 0.0 0.0 221936 1084 pts/0 S+ 18:14 0:00 grep --color=auto sleep 1000
# stop后台进程
[root@rocky dir1]# kill -19 4559
[root@rocky dir1]# ps aux | grep "sleep 1000"
root 4559 0.0 0.0 217080 860 pts/0 T 18:05 0:00 sleep 1000
root 4869 0.0 0.0 221936 1164 pts/0 S+ 18:14 0:00 grep --color=auto sleep 1000
[2]+ Stopped sleep 1000
[root@rocky dir1]# jobs
[2]+ Stopped sleep 1000
# 运行后台进程
[root@rocky dir1]# kill -18 4559
[root@rocky dir1]# jobs
[2]+ Running sleep 1000 &
3.6 计划任务
crontab命令可以实现计划任务,即周期性地执行一次命令,其主要用法如下。
每日凌晨1点,删除指定文件:
# 为当前用户编辑定时任务
[root@rocky cron]# crontab -e
* 1 * * * rm -rf /tmp/a.txt
no crontab for root - using an empty one
crontab: installing new crontab
# 查看当前用户定时任务
[root@rocky cron]# crontab -l
* 1 * * * rm -rf /tmp/a.txt
每月月初对指定文件进行压缩:
# 使用管道符添加定时任务
[root@rocky cron]# echo "* * * 1 * tar -zcf /tmp/aaa" | crontab
[root@rocky cron]# crontab -l
* * * 1 * tar -zcf /tmp/aaa