[实验] Redis 数据库集群的搭建

纪念:站主于 2019 年 11 月完成了此开源实验,并将过程中的所有命令经过整理和注释以后,形成以下教程

软件准备:

在 Redis 的官网上下载软件 Redis:

https://redis.io

在 rubygems 的官网上下载软件 rubygems

https://rubygems.org

正文:

步骤目录:

步骤一:规划拓扑
1.1 服务器列表
1.2 服务器列表简介

步骤二:系统环境要求

步骤三:所有数据库服务器安装 Redis 数据库
3.1 安装 Redis 数据库的相关依赖包
3.2 安装 Redis 数据库
3.2.1 解压安装包
3.2.2 进入安装包目录
3.2.3 编译安装包
3.2.4 安装软件包
3.2.5 进入配置目录
3.2.6 配置软件包

步骤四:搭建 Redis 数据库集群
4.1 修改所有服务器上的 Redis 数据库配置文件
4.2 重启所有服务器上的 Redis 数据库
4.2.1 关闭 Redis 数据库
4.2.2 开启 Redis 数据库
4.3 显示目前的集群信息
4.3.1 进入数据库
4.3.2 显示数据库是否可用
4.3.3 显示集群信息
4.4 部署 Redis 集群环境
4.4.1 部署 ruby 脚本运行环境
4.4.1.1 安装 ruby
4.4.1.2 升级 ruby
4.4.1.2.1 解压 ruby 安装包
4.4.1.2.2 进入 ruby 安装包目录
4.4.1.2.3 升级 ruby
4.4.1.3 安装 Redis 模块
4.4.2 部署 Redis 集群文件
4.4.2.1 创建 Redis 集群文件的目录
4.4.2.2 复制 Redis 集群文件
4.4.2.3 给 Redis 集群文件添加执行权限
4.5 创建 Redis 集群
4.6 显示集群中主机状态信息的方法
4.6.1 方法一
4.6.1.1 进入数据库
4.6.1.2 显示集群整体信息
4.6.1.3 显示集群主从关系
4.6.1.4 退出数据库
4.6.2 方法二
4.6.2.1 显示集群整体信息
4.6.2.2 显示集群主从关系

步骤五:Redis 集群创建失败的解决办法
5.1 关闭所有 Redis服务器的 Redis 服务
5.2 删除所有原来的 Redis 数据
5.3 重启 Redis 数据库
5.4 按照前面的步骤重新执行创建集群

步骤六:测试 Redis 集群
6.1 数据同步测试
6.1.1 进入数据库
6.1.2 确认现在的 Redis 数据库都是空的
6.1.3 在主 Redis 数据库上插入数据
6.1.4 查看刚插入的数据
6.2 高可用测试
6.2.1 模拟此时主库宕机后,对应的从库会自动升级为主库但需要 5 分钟的时间
6.2.2 等待 5 分钟后显示集群主从关系
6.2.3 主库恢复后会成为新主库的从库
6.2.4 再次显示集群主从关系

具体的操作步骤:

步骤一:规划拓扑
1.1 服务器列表

redis1 IP 地址:192.168.1.51 端口号:1051
redis2 IP 地址:192.168.1.52 端口号:1052
redis3 IP 地址:192.168.1.53 端口号:1053
redis4 IP 地址:192.168.1.54 端口号:1054
redis5 IP 地址:192.168.1.55 端口号:1055
redis6 IP 地址:192.168.1.56 端口号:1056

1.2 服务器列表简介

1) 总共 6 个数据库,3 个为主库,3 个为从库
2) 如果 1 个主库宕掉则它的从库自动成为主库
3) 宕掉的主库修复好后会成为新主库的从库
4) 如果半数或者半数以上的主库宕掉,集群则无法使用

(注意: Redis 集群最少要有 3 个主库)

步骤二:系统环境要求

1) 所有服务器的系统都需要是 CentOS 7 版本
2) 所有服务器都要关闭防火墙
3) 所有服务器都要关闭 SELinux
4) 所有服务器系统都要配置好可用的软件源
5) 需要按照拓扑图给对应的服务器配置好 IP 地址和主机名
6) 所有服务器都要可以相互 ping 通自己和对方的 IP 地址和主机名
7) 至少要有一台服务器可以访问外网

步骤三:所有数据库服务器安装 Redis 数据库
3.1 安装 Redis 数据库的相关依赖包

(分别在 redis1、redis2、redis3、redis4、redis5 和 redis6 上执行以下步骤)

# yum -y install gcc gcc-c++ make

3.2 安装 Redis 数据库
3.2.1 解压安装包

(分别在 redis1、redis2、redis3、redis4、redis5 和 redis6 上执行以下步骤)

# tar -zxf redis-5.0.5.tar.gz

(补充:这里要安装的 Redis 版本是 5.0.5)

3.2.2 进入安装包目录

(分别在 redis1、redis2、redis3、redis4、redis5 和 redis6 上执行以下步骤)

# cd redis-5.0.5/

(补充:这里要安装的 Redis 版本是 5.0.5)

3.2.3 编译安装包

(分别在 redis1、redis2、redis3、redis4、redis5 和 redis6 上执行以下步骤)

# make

3.2.4 安装软件包

(分别在 redis1、redis2、redis3、redis4、redis5 和 redis6 上执行以下步骤)
# make install

3.2.5 进入配置目录

(分别在 redis1、redis2、redis3、redis4、redis5 和 redis6 上执行以下步骤)
# cd utils/

3.2.6 配置软件包

(分别在 redis1、redis2、redis3、redis4、redis5 和 redis6 上执行以下步骤)

# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis server
Please select the redis port for this instance: [6379] 
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] 
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log] 
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] 
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server] 
Selected config:
Port           : 6379
Config file    : /etc/redis/6379.conf
Log file       : /var/log/redis_6379.log
Data dir       : /var/lib/redis/6379
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!

步骤四:搭建 Redis 数据库集群
4.1 修改所有服务器上的 Redis 数据库配置文件

(只在 redis1 上执行以下步骤)

# vim /etc/redis/6379.conf

将部分内容修改如下:

......
#bind 127.0.0.1
bind 192.168.1.51
......
port 1051
......
daemonize yes
......
pidfile /var/run/redis_1051.pid
......
cluster-enabled yes
......
cluster-config-file nodes-1051.conf
......
cluster-node-timeout 5000
......


补充:
1) 这里的 #bind 127.0.0.1 代表取消数据库可以被本地登录
2) 这里的 bind 192.168.1.51 是本机的 IP 地址
3) 这里的 port 1051 代表数据库使用到的端口是 1051,集群里的各个数据库端口号不能一样
4) 这里的 daemonize yes 代表以进程的形式启动
5) 这里的 pidfile /var/run/redis_1051.pid 代表使用的 PID 文件是 /var/run/redis_1051.pid,集群里的各个数据库 PID 文件不能一样
6) 这里的 cluster-enabled yes 代表启用集群,但是前面的 daemonize 必须也启用
7) 这里的 cluster-config-file nodes-1051.conf 代表使用的数据库配置文件是 nodes-1051.conf,集群里的各个数据库的配置文件不能一样
8) 这里的 cluster-node-timeout 5000 代表集群通信超时时间为 5000

(只在 redis2 上执行以下步骤)

# vim /etc/redis/6379.conf

将部分内容修改如下:

......
#bind 127.0.0.1
bind 192.168.1.52
......
port 1052
......
daemonize yes
......
pidfile /var/run/redis_1052.pid
......
cluster-enabled yes
......
cluster-config-file nodes-1052.conf
......
cluster-node-timeout 5000
......


补充:
1) 这里的 #bind 127.0.0.1 代表取消数据库可以被本地登录
2) 这里的 bind 192.168.1.52 是本机的 IP 地址
3) 这里的 port 1052 代表数据库使用到的端口是 1052,集群里的各个数据库端口号不能一样
4) 这里的 daemonize yes 代表以进程的形式启动
5) 这里的 pidfile /var/run/redis_1052.pid 代表使用的 PID 文件是 /var/run/redis_1052.pid,集群里的各个数据库 PID 文件不能一样
6) 这里的 cluster-enabled yes 代表启用集群,但是前面的 daemonize 必须也启用
7) 这里的 cluster-config-file nodes-1052.conf 代表使用的数据库配置文件是 nodes-1052.conf,集群里的各个数据库的配置文件不能一样
8) 这里的 cluster-node-timeout 5000 代表集群通信超时时间为 5000

(只在 redis3 上执行以下步骤)

# vim /etc/redis/6379.conf

将部分内容修改如下:

......
#bind 127.0.0.1
bind 192.168.1.53
......
port 1053
......
daemonize yes
......
pidfile /var/run/redis_1053.pid
......
cluster-enabled yes
......
cluster-config-file nodes-1053.conf
......
cluster-node-timeout 5000
......


补充:
1) 这里的 #bind 127.0.0.1 代表取消数据库可以被本地登录
2) 这里的 bind 192.168.1.53 是本机的 IP 地址
3) 这里的 port 1053 代表数据库使用到的端口是 1053,集群里的各个数据库端口号不能一样
4) 这里的 daemonize yes 代表以进程的形式启动
5) 这里的 pidfile /var/run/redis_1053.pid 代表使用的 PID 文件是 /var/run/redis_1053.pid,集群里的各个数据库 PID 文件不能一样
6) 这里的 cluster-enabled yes 代表启用集群,但是前面的 daemonize 必须也启用
7) 这里的 cluster-config-file nodes-1053.conf 代表使用的数据库配置文件是 nodes-1053.conf,集群里的各个数据库的配置文件不能一样
8) 这里的 cluster-node-timeout 5000 代表集群通信超时时间为 5000

(只在 redis4 上执行以下步骤)

# vim /etc/redis/6379.conf

将部分内容修改如下:

......
#bind 127.0.0.1
bind 192.168.1.54
......
port 1054
......
daemonize yes
......
pidfile /var/run/redis_1054.pid
......
cluster-enabled yes
......
cluster-config-file nodes-1054.conf
......
cluster-node-timeout 5000
......


补充:
1) 这里的 #bind 127.0.0.1 代表取消数据库可以被本地登录
2) 这里的 bind 192.168.1.54 是本机的 IP 地址
3) 这里的 port 1054 代表数据库使用到的端口是 1054,集群里的各个数据库端口号不能一样
4) 这里的 daemonize yes 代表以进程的形式启动
5) 这里的 pidfile /var/run/redis_1054.pid 代表使用的 PID 文件是 /var/run/redis_1054.pid,集群里的各个数据库 PID 文件不能一样
6) 这里的 cluster-enabled yes 代表启用集群,但是前面的 daemonize 必须也启用
7) 这里的 cluster-config-file nodes-1054.conf 代表使用的数据库配置文件是 nodes-1054.conf,集群里的各个数据库的配置文件不能一样
8) 这里的 cluster-node-timeout 5000 代表集群通信超时时间为 5000

(只在 redis5 上执行以下步骤)

# vim /etc/redis/6379.conf

将部分内容修改如下:

......
#bind 127.0.0.1
bind 192.168.1.55
......
port 1055
......
daemonize yes
......
pidfile /var/run/redis_1055.pid
......
cluster-enabled yes
......
cluster-config-file nodes-1055.conf
......
cluster-node-timeout 5000
......


补充:
1) 这里的 #bind 127.0.0.1 代表取消数据库可以被本地登录
2) 这里的 bind 192.168.1.55 是本机的 IP 地址
3) 这里的 port 1055 代表数据库使用到的端口是 1055,集群里的各个数据库端口号不能一样
4) 这里的 daemonize yes 代表以进程的形式启动
5) 这里的 pidfile /var/run/redis_1055.pid 代表使用的 PID 文件是 /var/run/redis_1055.pid,集群里的各个数据库 PID 文件不能一样
6) 这里的 cluster-enabled yes 代表启用集群,但是前面的 daemonize 必须也启用
7) 这里的 cluster-config-file nodes-1055.conf 代表使用的数据库配置文件是 nodes-1055.conf,集群里的各个数据库的配置文件不能一样
8) 这里的 cluster-node-timeout 5000 代表集群通信超时时间为 5000

(只在 redis6 上执行以下步骤)

# vim /etc/redis/6379.conf

将部分内容修改如下:

......
#bind 127.0.0.1
bind 192.168.1.56
......
port 1056
......
daemonize yes
......
pidfile /var/run/redis_1056.pid
......
cluster-enabled yes
......
cluster-config-file nodes-1056.conf
......
cluster-node-timeout 5000
......


补充:
1) 这里的 #bind 127.0.0.1 代表取消数据库可以被本地登录
2) 这里的 bind 192.168.1.56 是本机的 IP 地址
3) 这里的 port 1056 代表数据库使用到的端口是 1056,集群里的各个数据库端口号不能一样
4) 这里的 daemonize yes 代表以进程的形式启动
5) 这里的 pidfile /var/run/redis_1056.pid 代表使用的 PID 文件是 /var/run/redis_1056.pid,集群里的各个数据库 PID 文件不能一样
6) 这里的 cluster-enabled yes 代表启用集群,但是前面的 daemonize 必须也启用
7) 这里的 cluster-config-file nodes-1056.conf 代表使用的数据库配置文件是 nodes-1056.conf,集群里的各个数据库的配置文件不能一样
8) 这里的 cluster-node-timeout 5000 代表集群通信超时时间为 5000

4.2 重启所有服务器上的 Redis 数据库
4.2.1 关闭 Redis 数据库

(分别在 redis1、redis2、redis3、redis4、redis5 和 redis6 上执行以下步骤)

# redis-cli shutdown

4.2.2 开启 Redis 数据库

(分别在 redis1、redis2、redis3、redis4、redis5 和 redis6 上执行以下步骤)

# /etc/init.d/redis_6379 start

4.3 显示目前的集群信息

(此步骤可以在任意服务器上操作,这里以在 redis1 上操作为例)

4.3.1 进入数据库

(只在 redis1 上执行以下步骤)

# redis-cli -h 192.168.1.51 -p 1051

4.3.2 显示数据库是否可用

(只在 redis1 上执行以下步骤)

192.168.1.51:1051> ping
PONG

4.3.3 显示集群信息

(只在 redis1 上执行以下步骤)

192.168.1.51:1051> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:0
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0

4.4 部署 Redis 集群环境
4.4.1 部署 ruby 脚本运行环境

(此步骤可以在任意服务器上操作,但是这台服务器必须要可以访问外网,这里以在 redisA 上操作为例)

4.4.1.1 安装 ruby

(只在 redis1 上执行以下步骤)

# yum -y install ruby rubygems ruby-devel

4.4.1.2 升级 ruby
4.4.1.2.1 解压 ruby 安装包

(只在 redis1 上执行以下步骤)

# tar -xvf rubygems-3.0.6.tgz 

(补充:这里要安装的 rubygems 版本是 3.0.6)

4.4.1.2.2 进入 ruby 安装包目录

(只在 redis1 上执行以下步骤)

# cd rubygems-3.0.6

(补充:这里要安装的 rubygems 版本是 3.0.6)

4.4.1.2.3 升级 ruby

(只在 redis1 上执行以下步骤)

# ruby setup.rb

4.4.1.3 安装 Redis 模块

(只在 redis1 上执行以下步骤)

# gem install redis -v 3.3.5
Fetching: redis-3.3.5.gem (100%)
Successfully installed redis-3.3.5
Parsing documentation for redis-3.3.5
Installing ri documentation for redis-3.3.5
1 gem installed

4.4.2 部署 Redis 集群文件
4.4.2.1 创建 Redis 集群文件的目录

(只在 redis1 上执行以下步骤)

# mkdir /root/bin

4.4.2.2 复制 Redis 集群文件

(只在 redis1 上执行以下步骤)

# cp redis-5.0.5/src/redis-trib.rb /root/bin

4.4.2.3 给 Redis 集群文件添加执行权限

(只在 redis1 上执行以下步骤)

# chmod +x /root/bin/redis-trib.rb

4.5 创建 Redis 集群

(只在 redis1 上执行以下步骤)

# redis-cli --cluster create 192.168.1.51:1051 192.168.1.52:1052 192.168.1.53:1053 192.168.1.54:1054 192.168.1.55:1055 192.168.1.56:1056 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.1.55:1055 to 192.168.1.51:1051
Adding replica 192.168.1.56:1056 to 192.168.1.52:1052
Adding replica 192.168.1.54:1054 to 192.168.1.53:1053
M: 5d030ec05f9de86ebeedc1b035b2122addaa61d8 192.168.1.51:1051
   slots:[0-5460] (5461 slots) master
M: 7477c04d8ebf9d498ed5586d5f4e6d513fdb3c30 192.168.1.52:1052
   slots:[5461-10922] (5462 slots) master
M: c4f884e7e4ce6adb4f5bc4f6eb398680beb26089 192.168.1.53:1053
   slots:[10923-16383] (5461 slots) master
S: a5cddda6c1bc7c6d3397e17e1ba29571bb7a1657 192.168.1.54:1054
   replicates c4f884e7e4ce6adb4f5bc4f6eb398680beb26089
S: eac6a0586ad00375bea9aa352951c784be57e9ad 192.168.1.55:1055
   replicates 5d030ec05f9de86ebeedc1b035b2122addaa61d8
S: fd973bbcc376bfccf5888ba06dba97feb9ef1273 192.168.1.56:1056
   replicates 7477c04d8ebf9d498ed5586d5f4e6d513fdb3c30
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 192.168.1.51:1051)
M: 5d030ec05f9de86ebeedc1b035b2122addaa61d8 192.168.1.51:1051
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: eac6a0586ad00375bea9aa352951c784be57e9ad 192.168.1.55:1055
   slots: (0 slots) slave
   replicates 5d030ec05f9de86ebeedc1b035b2122addaa61d8
M: c4f884e7e4ce6adb4f5bc4f6eb398680beb26089 192.168.1.53:1053
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: 7477c04d8ebf9d498ed5586d5f4e6d513fdb3c30 192.168.1.52:1052
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: fd973bbcc376bfccf5888ba06dba97feb9ef1273 192.168.1.56:1056
   slots: (0 slots) slave
   replicates 7477c04d8ebf9d498ed5586d5f4e6d513fdb3c30
S: a5cddda6c1bc7c6d3397e17e1ba29571bb7a1657 192.168.1.54:1054
   slots: (0 slots) slave
   replicates c4f884e7e4ce6adb4f5bc4f6eb398680beb26089
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

4.6 显示集群中主机状态信息的方法
4.6.1 方法一
4.6.1.1 进入数据库

(只在 redis1 上执行以下步骤)

# redis-cli -h 192.168.1.51 -p 1051

4.6.1.2 显示集群整体信息

(只在 redis1 上执行以下步骤)

192.168.1.51:1051> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:30858
cluster_stats_messages_pong_sent:29942
cluster_stats_messages_sent:60800
cluster_stats_messages_ping_received:29937
cluster_stats_messages_pong_received:30858
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:60800

4.6.1.3 显示集群主从关系

(只在 redis1 上执行以下步骤)

192.168.1.53:1053> cluster nodes
eac6a0586ad00375bea9aa352951c784be57e9ad 192.168.1.55:1055@11055 slave 5d030ec05f9de86ebeedc1b035b2122addaa61d8 0 1574754846521 5 connected
a5cddda6c1bc7c6d3397e17e1ba29571bb7a1657 192.168.1.54:1054@11054 slave c4f884e7e4ce6adb4f5bc4f6eb398680beb26089 0 1574754846000 4 connected
fd973bbcc376bfccf5888ba06dba97feb9ef1273 192.168.1.56:1056@11056 slave 7477c04d8ebf9d498ed5586d5f4e6d513fdb3c30 0 1574754845819 6 connected
5d030ec05f9de86ebeedc1b035b2122addaa61d8 192.168.1.51:1051@11051 master - 0 1574754846822 1 connected 0-5460
7477c04d8ebf9d498ed5586d5f4e6d513fdb3c30 192.168.1.52:1052@11052 master - 0 1574754846000 2 connected 5461-10922
c4f884e7e4ce6adb4f5bc4f6eb398680beb26089 192.168.1.53:1053@11053 myself,master - 0 1574754844000 3 connected 10923-16383

4.6.1.4 退出数据库

(只在 redis1 上执行以下步骤)

192.168.1.51:1051> quit

4.6.2 方法二
4.6.2.1 显示集群整体信息

(只在 redis1 上执行以下步骤)

# redis-cli --cluster info 192.168.1.51 1051
192.168.1.51:1051 (5d030ec0...) -> 1 keys | 5461 slots | 1 slaves.
192.168.1.53:1053 (c4f884e7...) -> 1 keys | 5461 slots | 1 slaves.
192.168.1.52:1052 (7477c04d...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 3 keys in 3 masters.
0.00 keys per slot on average.

4.6.2.2 显示集群主从关系

(只在 redis1 上执行以下步骤)

# redis-cli --cluster check 192.168.1.51 1051
192.168.1.51:1051 (5d030ec0...) -> 1 keys | 5461 slots | 1 slaves.
192.168.1.53:1053 (c4f884e7...) -> 1 keys | 5461 slots | 1 slaves.
192.168.1.52:1052 (7477c04d...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 3 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.1.51:1051)
M: 5d030ec05f9de86ebeedc1b035b2122addaa61d8 192.168.1.51:1051
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: eac6a0586ad00375bea9aa352951c784be57e9ad 192.168.1.55:1055
   slots: (0 slots) slave
   replicates 5d030ec05f9de86ebeedc1b035b2122addaa61d8
M: c4f884e7e4ce6adb4f5bc4f6eb398680beb26089 192.168.1.53:1053
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: 7477c04d8ebf9d498ed5586d5f4e6d513fdb3c30 192.168.1.52:1052
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: fd973bbcc376bfccf5888ba06dba97feb9ef1273 192.168.1.56:1056
   slots: (0 slots) slave
   replicates 7477c04d8ebf9d498ed5586d5f4e6d513fdb3c30
S: a5cddda6c1bc7c6d3397e17e1ba29571bb7a1657 192.168.1.54:1054
   slots: (0 slots) slave
   replicates c4f884e7e4ce6adb4f5bc4f6eb398680beb26089
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

步骤五:Redis 集群创建失败的解决办法
5.1 关闭所有 Redis服务器的 Redis 服务

(只在加入集群失败的服务器上执行以下步骤)

# redis-cli -h <IP address of this server> -p <port number used by redis of this server> shutdowm

5.2 删除所有原来的 Redis 数据

(只在加入集群失败的服务器上执行以下步骤)

# rm -rf /var/lib/redis/6379/*

5.3 重启 Redis 数据库

(只在加入集群失败的服务器上执行以下步骤)

# /etc/init.d/redis_6379 start

5.4 按照前面的步骤重新执行创建集群

(只在加入集群失败的服务器上执行以下步骤)

(步骤略)

步骤六:测试 Redis 集群
6.1 数据同步测试
6.1.1 进入数据库

(只在 redis1 上执行以下步骤)

# redis-cli -h 192.168.1.51 -p 1051

(只在 redis2 上执行以下步骤)

# redis-cli -h 192.168.1.52 -p 1052

(只在 redis3 上执行以下步骤)

# redis-cli -h 192.168.1.53 -p 1053

(只在 redis4 上执行以下步骤)

# redis-cli -h 192.168.1.54 -p 1054

(只在 redis5 上执行以下步骤)

# redis-cli -h 192.168.1.55 -p 1055

(只在 redis6 上执行以下步骤)

# redis-cli -h 192.168.1.56 -p 1056

6.1.2 确认现在的 Redis 数据库都是空的

(只在 redis1 上执行以下步骤)

192.168.1.51:1051> keys *

(只在 redis2 上执行以下步骤)

192.168.1.51:1052> keys *

(只在 redis3 上执行以下步骤)

192.168.1.51:1053> keys *

(只在 redis4 上执行以下步骤)

192.168.1.51:1054> keys *

(只在 redis5 上执行以下步骤)

192.168.1.51:1055> keys *

(只在 redis6 上执行以下步骤)

192.168.1.51:1056> keys *

6.1.3 在主 Redis 数据库上插入数据

(补充:本次的主数据库是 redis1、redis2、redis3)

(只在 redis1 上执行以下步骤)

192.168.1.51:1051> set aa 101
-> Redirected to slot [15495] located at 192.168.1.53:1053
OK

(只在 redis2 上执行以下步骤)

192.168.1.52:1052> set bb 102
-> Redirected to slot [3300] located at 192.168.1.51:1051
OK

(只在 redis3 上执行以下步骤)

192.168.1.53:1053> set ff 103
-> Redirected to slot [7365] located at 192.168.1.52:1052
OK

6.1.4 查看刚插入的数据

(只在 redis1 上执行以下步骤)

192.168.1.51:1051> keys *
1) "aa"

(只在 redis2 上执行以下步骤)

192.168.1.51:1052> keys *
1) "bb"

(只在 redis3 上执行以下步骤)

192.168.1.51:1053> keys *
1) "ff"

(只在 redis4 上执行以下步骤)

192.168.1.51:1054> keys *
1) "ff"

(只在 redis5 上执行以下步骤)

192.168.1.51:1055> keys *
1) "aa"

(只在 redis6 上执行以下步骤)

192.168.1.51:1056> keys *
1) "bb"


补充:
1) 对应的从库会自动同步主库的数据
2) 本次的主数据库是 redis1(从库是 redis5)、redis2(从库是 redis6)、redis3(从库是 redis4)
)

6.2 高可用测试
6.2.1 模拟此时主库宕机后,对应的从库会自动升级为主库但需要 5 分钟的时间

(只在模拟宕机的主库服务器上执行以下步骤)

# redis-cli -h <IP address of this server> -p <port number used by redis of this server> shutdown

6.2.2 等待 5 分钟后显示集群主从关系

(只在 redis1 上执行以下步骤)

# redis-cli --cluster check 192.168.1.51 1051

6.2.3 主库恢复后会成为新主库的从库

(只在模拟宕机的主库服务器上执行以下步骤)

# /etc/init.d/redis_6379 start

6.2.4 再次显示集群主从关系

(只在 redis1 上执行以下步骤)

# redis-cli --cluster check 192.168.1.51 1051

[命令] Linux 命令 sed (修改和显示文件的行)

内容目录:

内容一:sed 基础
1.1 sed 的工作原理
1.2 sed 格式
1.3 sed 选项
1.4 sed 的参数

内容二:sed 使用 p 参数、P 参数、n 参数、N 参数和 = 参数显示某些行数据的案例
2.1 显示第 2 行的内容
2.2 显示第 2 行到第 4 行的内容
2.3 显示不是第 1 行的内容
2.4 显示最后 1 行的内容
2.5 显示包含 eternalcenter 的内容
2.6 显示以 eternalcenter 结尾的内容
2.7 显示包含 eternalcenter 的行的行号,并将此行的上一行的内容,本行的内容和下一行的内容显示出来
2.8 显示包含从 2000 到 2007 点行
2.9 显示从 2022-01-01 00:00:00 到 2022-02-22 00:00:00 到内容
2.10 显示总行数
2.11 显示从 2022-01-01 00:00:00 到最后的内容
2.12 以非标准输出的方式显示每 1 行是第几行,在行数后面以标准输出的方式显示行的内容,但是不显示第 1 行的内容
2.13 以非标准输出的方式显示每 1 行是第几行,在行数后面以标准输出的方式显示行的内容,但是不显示第 1 行的内容
2.14 添加行号并显示所有内容
2.15 显示奇数行
2.16 显示偶数行
2.17 显示所有行是第几行,行数后面跟行的内容
2.18 显示所有行是第几行,只显示行数
2.19 显示包含 eternalcenter 内容的行是第几行
2.20 显示所有空行是第几行
2.21 合并相同的行,也就是相同行去重

内容三:sed 使用 a 参数在某 1 行下面追加数据的案例
3.1 在第 2 行下面追加 1 行 eternalcenter
3.2 在 abc 那 1 行下面添加 1 行 eternalcenter
3.3 在 test.txt 文件里在以 a 开头的行下面添加 eternalcenter
3.4 在以 [a] 开头的行下面添加 eternalcenter
3.5 在最后 1 行下面添加 eternalcenter
3.6 在 eternalcenter 这 1 行后面添加 eternalcentre、mingyuzhu 和 zhumingyu 3 行

内容四:sed 使用 i 参数在某 1 行上面插入数据的案例
4.1 在第 2 行上面插入 1 行 eternalcenter
4.2 在 abc 那 1 行上面添加 1 行 eternalcenter
4.3 在以 a 开头的行上面添加 eternalcenter
4.4 在以 [a] 开头的行上面添加 eternalcenter
4.5 在最后 1 行上面添加 eternalcenter

内容五:sed 使用 c 参数替换某些行数据的案例
5.1 将第 2 行替换成 eternalcenter
5.2 将 abc 那 1 行替换成 eternalcenter
5.3 将以 a 开头的那 1 行替换成 eternalcenter
5.4 将以 [a] 开头的那 1 行替换成 eternalcenter
5.5 将以 eternalcentre 开头的那 1 行替换成 eternalcenter ALL=(ALL) NOPASSWD: ALL

内容六:sed 使用 d 参数删除某些行的案例
6.1 删除第 2 行
6.2 删除包含 abc 的那 1 行
6.3 删除以 a 开头的那 1 行
6.4 删除以 [a] 开头的那 1 行
6.5 删除第 2 行到第 4 行

内容七:sed 使用 s 或者 y 参数替换某些行某些数据的案例
7.1 将所有行的第一个 eternalcentre 换成 eternalcenter
7.2 将所有行的所有 eternalcentre 换成 eternalcenter
7.3 将包含 eternalcentre 的行换成 eternalcenter
7.4 将第 3 行的第 2 个 eternalcentre 换成 eternalcenter
7.5 在所有行前面添加 eternalcenter
7.6 在所有行后面添加 eternalcenter
7.7 将第 2 行替换成 eternalcenter
7.8 将最后 1 行替换成 eternalcenter
7.9 将第 2 到第 3 行替换成 eternalcenter
7.10 将 eternalcenter 前面的数据和后面的数据对调位置
7.11 所有行前后字符串互调
7.12 删除每行的第 1 个字符和最后 1 个字符
7.13 删除每行的第 2 个字符和最后 1 个字符
7.14 删除所有行的数字和空格
7.15 删除 1 行不是最后 1 行包含 eternalcenter 的行
7.16 将所有的大写字母都添加括号
7.17 在第 7 行和第 9 行前面添加 “#”
7.18 删除第 1 个空格
7.19 在以打写字母开头,中间是小写字母,以数字结尾的行里在小写字母和数字之间插入 ok
7.20 在以打写字母开头,中间是小写字母,以数字结尾的行里在小写字母和数字之间插入 ok,并将数字替换到最前面
7.21 删除 2022-01-01 字符里的横杠 “-”
7.22 将日期的年月日以空格分开
7.23 合并上下行
7.24 将以反斜杠号 “\” 结尾的行与下 1 行合并在一起并以空格进行分隔 (只合并一次)
7.25 将以反斜杠号 “\” 结尾的行与下 1 行合并在一起并以空格进行分隔 (能合并多少次就合并多少次)
7.26 若某行以 = 开头则合并到上 1 行并将等于号 “=” 替换成空格
7.27 行列转换,并且将第 1 行相同的列,行列转换以后合并,也就是行列转换以后没有第 1 列相互重复的行 (指定 1 列是 1 个 5 个字符长度的字节)
7.28 行列转换,并且将第 1 行相同的列,行列转换以后合并,也就是行列转换以后没有第 1 列相互重复的行 (指定 1 列是以 .com 结尾)
7.29 行列转换,并且将第 1 行相同的列,行列转换以后合并,也就是行列转换以后没有第 1 列相互重复的行 (指定 1 列是以空格 “ ” 结尾)

内容八:sed 使用 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数第案例
8.1 sed 的工作原理
8.2 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的讲解
8.2.1 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的作用简介
8.2.2 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的功能示意图
8.3 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的使用案例
8.3.1 将第 1 行的数据添加到第 3 行后面
8.3.2 将第 1 行的数据替换第 3 行
8.3.3 将第 1 行和第 2 行的数据添加到第 3 行后面
8.3.4 将第 1 行和第 2 行的数据替换第 3 行
8.3.5 将第 1 个以 a 开头的行的数据添加到第 3 行后面
8.3.6 将第 1 个和第 2 个以 a 开头的行的数据添加到第 3 行后面
8.3.7 将 eternalcenter 的 eternal 和 center 以空格分开

内容九:sed 一次匹配多个参数的案例

内容十:sed r 参数和 w 参数读取和写入文件
10.1 将 test2.txt 文件里的内容添加到 test1.txt 文件里内容的第3 行后面
10.2 将 test1.txt 文件里内容的第三行保存到 test2.txt 中

内容十一:sed q 参数退出当前执行的内容
11.1 执行完第 5 行后退出
11.2 执行完包含 eternalcenter 的行后退出
11.3 执行完第 3 行后退出,并将退出代码设置为 3

内容十二:sed b 参数和 t 参数设置标签分支
12.1 如果某行不包含 eternalcenter 则将此行中内容的 0 换成 1,否则将此行中内容的 0 换成 2
12.2 如果某行包含 eternalcenter 则将此行中内容的 0 换成 1,否则将此行中内容的 0 换成 2

具体的内容:

内容一:sed 基础
1.1 sed 的工作原理

1) 从第 1 行开始 1 行 1 行地读取文件里的内容
2) 每读取 1 行就将内容存入到 pattern space (模型空间) 里面
3) 在 pattern space (模型空间) 中执行 sed 命令
4) 再显示 pattern space (模型空间) 中的内容然后将其清空
5) 之后重复以上操作再开始读取文件里的下 1 行
6) pattern space (模型空间) 里的内容可以存储到 hold space 里面

1.2 sed 格式

# sed <option> <parameter> <file>

1.3 sed 选项

1) -n 或 –quiet 或 –silent 仅显示处理后的内容,没处理的内容就不显示了,也就是仅显示非标准输出的内容
2) -i 实现数据的变更
3) -e <script> 或 –expression=<script> 这样可以一次匹配多个参数
4) -r 支持扩展正则
5) -f <script file> 或 –file=<script file> 以指定的脚本文件来处理输入的文件
6) -h 或 –help 显示帮助内容
7) -V 或 –version 显示版本信息


补充:
1) pattern space (模型空间) 相当于处理内容的流水线
2) hold space (保持空间) 相当于暂时存储内容的仓库

1.4 sed 的参数

1) p 先将每行的内容以标准输出的形式显示 1 遍,再将每行的内容以非标准输出的形式再显示 1 遍。不改变是否跳过下 1 行的属性,也就是如果前面有一个 N 参数,则跳过往下第 1 行接着执行往下第 2 行,如果前面没有任何参数,则直接执行往下第 1 行
2) P 先将每行的内容以非标准输出的形式再显示 1 遍,但是如果是 2 行组合在一起的话只显示第 1 行的内容,也就是只显示分行符 “/n” 之前的内容,再将每行的内容以标准输出的形式显示 1 遍。不改变是否跳过下 1 行的属性,也就是如果前面有一个 N 参数,则跳过往下第 1 行接着执行往下第 2 行,如果前面没有任何参数,则直接执行往下第 1 行
3) n 将每行的内容以标准输出的形式显示 1 遍,并提前读取下 1 行的内容,将下 1 行的内容覆盖当前行的 pattern space (模型空间),也就是下 1 行变成了当前行,再将当前行的内容以标准输出的形式显示一遍 (如果此时得到的内容是非标准的形式则不显示)。然后跳过往下第 1 行接着执行往下第 2 行。另外,如果往下 1 行不存在则直接停止所有命令,如果当前面的条件匹配时则放弃所有后面的命令
4) N 提前预读下 1 行,将下 1 行的内容添加到本行的 pattern space (模型空间) 后面,但是本行的内容和下 1 行的内容之间依旧存在分行符 “/n”,再将当前行的内容以标准输出的形式显示一遍。然后跳过下第 1 行接着执行往下第 2 行。另外,如果下 1 行不存在则以标准的形式显示当前 pattern space (模型空间) 里的内容并直接停止所有命令,如果当前面的条件不匹配时则放弃执行 N 命令直接执行后面的命令
5) = 以非标准输出的形式显示每 1 行是第几行,在行数后面以标准输出的形式显示行的内容
6) a 在某 1 行下面追加 1 行的内容
7) i 在某 1 行上面插入 1 行的内容
8) c 替换某 1 行的内容
9) g 将 hold space (保持空间) 中的内容拷贝到 pattern space (模型空间) 中,原来 pattern space (模型空间) 里的内容被清除
10) G 将 hold space (保持空间) 中的内容 append (添加) 到 pattern space (模型空间) 分行符 “/n” 后
11) h 将 pattern space (模型空间) 中的内容拷贝到 hold space (保持空间) 中,原来的 hold space (保持空间)里的内容被清除
12) H 将 pattern space (模型空间) 中的内容 append (添加) 到 hold space (保持空间) 分行符 “/n” 后
13) d 删除 pattern space (模型空间) 中的所有行,并执行下 1 行
14) D 删除 pattern space (模型空间) 中的第 1 行,也就是分行符 “/n” 之前的内容,如果删除后还有内容,则以此内容作为新的 1 行往下执行
15) s 替换某行的某些内容
16) y 替换某行的某些内容,和 s 的作用一样,但是功能没有 s 丰富
17) x 将当前 hold space (保持空间) 和 pattern space (模型空间) 内容互换,hold space (保持空间) 用来保存临时内容, pattern space (模型空间) 是本行的内容,注意 hold space (保持空间) 和 pattern space (模型空间) 的内容互换并不改变这些内容是第几行的,例如在 pattern space (模型空间) 里的内容是第 3 行的,则需要 3p
18) r 读取某一个文件里的内容
19) w 将内容写入一个文件
20) q 退出,前面可以跟退出的条件,后面可以跟退出代码
21) b 参数,设置标签分支,如果条件不成立,则对标签的位置进行跳转,如果标签省略了,则分支会一直到末尾
22) t 参数,设置标签分支,如果条件成立,则对标签的位置进行循环跳转,直到所有可进行的操作都完成后才停止,如果标签省略了则标签分支会一直到头部。在 t 和变迁之间的步骤是会循环执行的区域


注意:
1) 当多个参数进行组合时,多次标准输出最后会合并成只显示一次
2) 当多个参数进行组合时,当一个参数后面还有参数时,产生的最后一次显示不会直接显示而是传输给下一个参数进行处理,如果此次显示是非输出的形式,传递给下一个参数处理以后也会以非输出的形式显示

内容二:sed 使用 p 参数、P 参数、n 参数、N 参数和 = 参数显示某些行数据的案例
2.1 显示第 2 行的内容

# sed -n 2p test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.2 显示第 2 行到第 4 行的内容

# sed -n 2,4p test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.3 显示不是第 1 行的内容

# sed 1!p test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.4 显示最后 1 行的内容

# sed -n '$p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

或者:

# sed 'N;D' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.5 显示包含 eternalcenter 的内容

# sed -n '/eternalcenter/p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.6 显示以 eternalcenter 结尾的内容

# sed -n '/eternalcenter$/p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.7 显示包含 eternalcenter 的行的行号,并将此行的上一行的内容,本行的内容和下一行的内容显示出来

# sed -n -e '/eternalcenter/{=;x;1!p;g;$!N;p;D;}' -e h test.txt


补充:
1) 当执行到包含 eternalcenter 内容的行时
2) 执行 /eternalcenter/ 判断当前包含 eternalcenter 内容则为真,如果为真,执行 = 参数,以非标准输出的形式传输每 1 行是第几行,在行数后面以标准输出的形式传输行的内容,此时这些内容存放在 pattern space (模型空间) 中并传输给 x 参数
3) 执行 x 参数,将当前 hold space (保持空间) 和 pattern space (模型空间) 内容互换,并传输给 p 参数。在执行 x 参数前 hold space (保持空间) 里的内容是由上一行执行 h 参数时保存的,所以执行 x 参数后 pattern space (模型空间) 的内容是上一行的内容。注意 hold space (保持空间) 和 pattern space (模型空间) 的内容互换并不改变这些内容是第几行的
4) 执行 1! 判断当前行不是第 1 行则为真,如果不是第 1 行,如果执行 p 参数,将此时 pattern space (模型空间) 的内容以标准输出的形式进行显示,再将 pattern space (模型空间) 的内容以非标准输出的形式传输给 g 参数
5) 执行 g 参数,将 hold space (保持空间) 中的内容拷贝到 pattern space (模型空间) 中,原来 pattern space (模型空间) 里的内容被清除,将此时的 pattern space (模型空间) 的内容传输给 N 参数
6) 执行 $! 判断当前行不是最后 1 行则为真,如果为真,执行 N 参数,将下一行的内容添加到本行内容的后面,但是两行之间存在分行符 “/n”,保存到 pattern space (模型空间),将此时的 pattern space (模型空间) 的内容以非标准输出的形式传输给 p 参数
7) 执行 p 参数,将 pattern space (模型空间) 里的内容以标准的形式显示,再将 pattern space (模型空间) 里的内容以非标准的形式传输给 D 参数
8) 执行 D 参数,删除 pattern space (模型空间) 中的第 1 行,也就是分行符 “/n” 之前的内容,并将此时 pattern space (模型空间) 里的内容传输给参数 h
9) 执行 h 参数,将 pattern space (模型空间) 中的内容拷贝到 hold space (保持空间) 中,原来的 hold space (保持空间)里的内容被清除
10) 这里的 test.txt 是要被 sed 操作的测试文件

2.8 显示包含从 2000 到 2007 点行

# sed -n '/2000/,/2007/p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

(注意:test.txt 里必须要有包含 2000 内容和 2007 内容的行此命令才会生效)

2.9 显示从 2022-01-01 00:00:00 到 2022-02-22 00:00:00 的内容

# sed -n  '/2022-01-01 00:00:00/,/2022-02-22 00:00:00/p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

(注意:test.txt 里必须要有包含 2022-01-01 00:00:00 内容和 2022-02-22 00:00:00 内容的行此命令才会生效)

2.10 显示从 2022-01-01 00:00:00 到最后的内容

# sed '/2019-01-01/,$' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

(注意:test.txt 里必须要有包含 2019-01-01 内容的行此命令才会生效)

2.11 显示总行数

# sed -n $= test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.12 以非标准输出的方式显示每 1 行是第几行,在行数后面以标准输出的方式显示行的内容,但是不显示第 1 行的内容

# sed -n '{=;1!p}' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.13 以非标准输出的方式显示每 1 行是第几行,在行数后面以标准输出的方式显示行的内容,但是不显示第 1 行的内容

# sed -n '{=;2!p}' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.14 添加行号并显示所有内容

# sed = test.txt | sed 'N;s/\n/:/'

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.15 显示奇数行

# sed -n 'p;n' test.txt


补充:
1) 执行第 1 行,执行 p 参数,将第 1 行的内容以标准输出的形式进行显示,再将第 1 行的内容以非标准输出的形式传输给 n 参数,再执行 n 参数,将第 1 行的内容以标准输出的形式进行显示 (但是这里传输给 n 参数的内容已经是非标准的形式了,所以这里变为以非标准的形式进行显示),再将第 1 行的内容被第 2 行的内容覆盖,再将第 1 行的内容以标准输出的形式显示 1 遍 (但是这里传输给 n 参数的内容已经是非标准的形式了,所以这里不再进行显示),再跳过第 2 行再直接执行第 3 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
2) 执行第 3 行,执行 p 参数,将第 3 行的内容以标准输出的形式进行显示,再将第 3 行的内容以非标准输出的形式传输给 n 参数,再执行 n 参数,将第 3 行的内容以标准输出的形式进行显示 (但是这里传输给 n 参数的内容已经是非标准的形式了,所以这里变为以非标准的形式进行显示),再将第 3 行的内容被第 4 行的内容覆盖,再将第 1 行的内容以标准输出的形式显示 1 遍 (但是这里传输给 n 参数的内容已经是非标准的形式了,所以这里不再进行显示),再跳过第 4 行再直接执行第 5 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
3) 以此类推
4) 当执行到最后 1 行时,按照之前的逻辑,如果是奇数行则显示当前行的内容,如果是偶数行则跳过
5) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed -n '$!N;P' test.txt


补充:
1) $! 作用是判断当前行不是最后 1 行时执行后面的命令
2) 执行第 1 行,执行 $! 判断当前行不是最后 1 行则为真,第 1 行不是最后 1 行,执行 N 命令,将第 2 行的内容添加到第 1 行的内容的后面,但是第 1 行和第 2 行之间存在分行符 “/n”,再将当前行的内容以标准输出的形式传输给 P 参数,再执行 P 命令,将此时第 1 行的内容以标准输出的形式进行显示,再将分行符 “/n” 之前的所有内容 (也就是最早是第 1 行的内容) 以非标准输出的形式显示出来,并跳过第 2 行再直接执行第 3 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
3) 执行第 3 行,执行 $! 判断当前行不是最后 3 行则为真,第 3 行不是最后 1 行,执行 N 命令,将第 4 行的内容添加到第 3 行的内容的后面,但是第 3 行和第 4 行之间存在分行符 “/n”,再将当前行的内容以标准输出的形式传输给 P 参数,再执行 P 命令,将此时第 3 行的内容以标准输出的形式进行显示,再将分行符 “/n” 之前的所有内容 (也就是最早是第 3 行的内容) 以非标准输出的形式显示出来,并跳过第 3 行再直接执行第 4 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
4) 以此类推
5) 当执行到最后 1 行时,因为已经没有下 1 行了,所以停止命令
6) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed 'n;d' test.txt


补充:
1) 执行第 1 行,执行 n 参数,将第 1 行的内容以标准输出的形式进行显示,再将第 1 行的内容被第 2 行的内容替代,再将被替代的内容传输给 d 参数,再执行 d 参数将第 2 行的内容删除掉。并跳过第 2 行直接执行第 3 行
2) 执行第 3 行,执行 n 参数,将第 3 行的内容以标准输出的形式进行显示,再将第 3 行的内容被第 4 行的内容替代,再将被替代的内容传输给 d 参数,再执行 d 参数将第 4 行的内容删除掉。并跳过第 4 行直接执行第 5 行
3) 以此类推
4) 当执行到最后 1 行时,因为已经没有下 1 行了,所以停止命令
5) 这里的 test.txt 是要被 sed 操作的测试文件

2.16 显示偶数行

# sed -n 'n;p' test.txt


补充:
1) 执行第 1 行,执行 n 参数,将第 1 行的内容以标准输出的形式进行显示,再将第 1 行的内容被第 2 行的内容替代,再将被替代的内容传输给 p 参数,再执行 p 参数,将第 2 行的内容以标准的形式显示,再将第 2 行的内容以非标准的形式显示。并跳过第 2 行再直接执行第 3 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
2) 执行第 3 行,执行 n 参数,将第 3 行的内容以标准输出的形式进行显示,再将第 3 行的内容被第 4 行的内容替代,再将被替代的内容传输给 p 参数,再执行 p 参数,将第 4 行的内容以标准的形式显示,再将第 4 行的内容以非标准的形式显示。并跳过第 4 行再直接执行第 5 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
3) 以此类推
4) 当执行到最后 1 行时,因为已经没有下 1 行了,所以停止命令
5) 这里的 test.txt 是要被 sed 操作的测试文件

2.17 显示所有行是第几行,行数后面跟行的内容

# sed = test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.18 显示所有行是第几行,只显示行数

# sed -n test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.19 显示包含 eternalcenter 内容的行是第几行

# sed -n '/eternalcenter/=' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.20 显示所有空行是第几行

# sed -n '/^$/=' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.21 合并相同的行,也就是相同行去重

# sort test.txt | sed '$!N;/^\(.*\)\n\1$/!P;D'

(
补充:
1) 执行 sort 将所有的行进行排序将相同的行排在一起,并结果输出给 sed
2) 执行第 1 行,执行 $! 判断当前行不是最后 1 行则为真,第 1 行不是最后 1 行,执行 N 参数,将第 2 行的内容添加到第 1 行的内容的后面,但是第 1 行和第 2 行之间存在分行符 “/n”,再将组合后的内容传输给 P 参数,再执行 /^(.*)\n\1$/! 判断当前行 \n 前面和后面不一样则为真,当为假时则直接不执行将内容传输给 D 参数,当为真时,执行 P 参数,先将第 1 行的内容以非标准输出的形式显示一遍,但是如果是 2 行组合在一起的话只显示第 1 行的内容,也就是只显示分行符 “/n” 之前的内容,再将第 1 行的内容以标准输出的形式传输给 D 参数,执行 D 参数,删除内容中的第 1 行,也就是分行符 “/n” 之前的内容,如果删除后还有内容,则以此内容作为新的 1 行往下执行第 2 行,如果删除后没有内容了,则跳过第 2 行直接执行第 3 行
3) 以此类推
4) 当执行到最后 1 行时,因为已经没有下 1 行了,所以停止命令
5) 这里的 test.txt 是要被 sed 操作的测试文件
)

内容三:sed 使用 a 参数在某 1 行下面追加数据的案例
3.1 在第 2 行下面追加 1 行 eternalcenter

# sed "2a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.2 在 abc 那 1 行下面添加 1 行 eternalcenter

# sed "/abc/a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.3 在 test.txt 文件里在以 a 开头的行下面添加 eternalcenter

# sed "/^a/a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.4 在以 [a] 开头的行下面添加 eternalcenter

# sed "/^\[a\]/a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.5 在最后 1 行下面添加 eternalcenter

# sed "$a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.6 在 eternalcenter 这 1 行后面添加 eternalcentre、mingyuzhu 和 zhumingyu 3 行

# sed '/eternalcenter/a eternalcentre\nmingyuzhu\nzhumingyu' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容四:sed 使用 i 参数在某 1 行上面插入数据的案例
4.1 在第 2 行上面插入 1 行 eternalcenter

# sed "2i eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

4.2 在 abc 那 1 行上面添加 1 行 eternalcenter

# sed "/abc/i eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

4.3 在以 a 开头的行上面添加 eternalcenter

# sed "/^a/i eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

4.4 在以 [a] 开头的行上面添加 eternalcenter

# sed "/^\[a\]/i eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

4.5 在最后 1 行上面添加 eternalcenter

# sed "$a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容五:sed 使用 c 参数替换某些行数据的案例
5.1 将第 2 行替换成 eternalcenter

# sed "2c\ eternalcenter" test.txt

或者:

# sed "2ceternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

5.2 将 abc 那 1 行替换成 eternalcenter

# sed "/abc/c\ eternalcenter" test.txt

或者:

# sed "/abc/ceternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

5.3 将以 a 开头的那 1 行替换成 eternalcenter

# sed "/^a/c\ eternalcenter" test.txt

或者:

# sed "/^a/ceternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

5.4 将以 [a] 开头的那 1 行替换成 eternalcenter

# sed "/^\[a\]/c\ eternalcenter" test.txt

或者:

# sed "/^\[a\]/ceternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

5.5 将以 eternalcentre 开头的那 1 行替换成 eternalcenter ALL=(ALL) NOPASSWD: ALL

# sed "/^eternalcentre/c\ eternalcenter\ ALL=\(ALL\)\ NOPASSWD:\ ALL" test.txt

或者:

# sed "/^eternalcentre/c\eternalcenter\ ALL=\(ALL\)\ NOPASSWD:\ ALL" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容六:sed 使用 d 参数删除某些行的案例
6.1 删除第 2 行

# sed 2d test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

6.2 删除包含 abc 的那 1 行

# sed /"abc"/d test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

6.3 删除以 a 开头的那 1 行

# sed /"^a"/d test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

6.4 删除以 [a] 开头的那 1 行

# sed /"^\[a\]"/d test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

6.5 删除第 2 行到第 4 行

# sed '2,4d' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容七:sed 使用 s 或者 y 参数替换某些行某些数据的案例
7.1 将所有行的第一个 eternalcentre 换成 eternalcenter

# sed 's/eternalcentre/eternalcneter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.2 将所有行的所有 eternalcentre 换成 eternalcenter

# sed 's/eternalcentre/eternalcneter/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.3 将包含 eternalcentre 的行换成 eternalcenter

# sed 's/.*eternalcentre.*/eternalcneter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.4 将第 3 行的第 2 个 eternalcentre 换成 eternalcenter

# sed '3s/eternalcentre/eternalcenter/2' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.5 在所有行前面添加 eternalcenter

# sed 's/^/eternalcenter/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

或者:

# sed 's/^/eternalcenter&/g test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.6 在所有行后面添加 eternalcenter

# sed 's/$/eternalcenter/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

或者:

# s/$/&eternalcenter/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.7 将第 2 行替换成 eternalcenter

# sed '2s/.*/eternalcenter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.8 将最后 1 行替换成 eternalcenter

# sed '$s/.*/eternalcenter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.9 将第 2 到第 3 行替换成 eternalcenter

# sed '2,3s/.*/eternalcenter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.10 将 eternalcenter 前面的数据和后面的数据对调位置

# sed "s/^\(.*\)\(eternalcenter\)\(.*\)$/\3\2\1/" test.txt

或者:

# sed -r "s/(.*)(eternalcenter)(.*)/\3\2\1/" test.txt

或者:

# sed -r "s/(.*)((eternal)(center))(.*)/\5\2\1/" test.txt

(补充:这里以 (.*) 是 1,((eternal)(center)) 是 2,(eternal) 是 3,(center) 是 4,(.*) 是 5 为例,这里的 test.txt 是要被 sed 操作的测试文件)

7.11 所有行前后字符串互调

# sed -r 's/.*/&\n/g;:a;s/(.*)(.)\n(.*)/\1\n\3\2/g;ta;s/^\n//g' test.txt


补充:
1) 执行 s/.*/&\n/g 在每行行尾添加换行符 “\n”
2) 执行 a 参数和 ta 参数,将从 :a 到 ta 之间的内容以后面的操作作为循环条件只要还能继续执行就一直循环,每次执行 s/(.*)(.)\n(.*)/\1\n\3\2/g,将此时所有行换行符 “\n” 之前的内容里最后一个字母移动到所有行换行符 “\n” 之后到内容里最后一个位置
3) 执行 s/^\n//g 删除所有行的换行符 “\n”
4) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed -r 's/.*/&\n/g;:b;s/(.*)(.)\n(.*)/\1\n\3\2/g;tb;s/^\n//g' test.txt


补充:
1) 执行 s/.*/&\n/g 在每行行尾添加换行符 “\n”
2) 执行 b 参数和 tb 参数,将从 :b 到 tb 之间的内容以后面的操作作为循环条件只要还能继续执行就一直循环,每次执行 s/(.*)(.)\n(.*)/\1\n\3\2/g,将此时所有行换行符 “\n” 之前的内容里最后一个字母移动到所有行换行符 “\n” 之后到内容里最后一个位置
3) 执行 s/^\n//g 删除所有行的换行符 “\n”
4) 这里的 test.txt 是要被 sed 操作的测试文件

7.12 删除每行的第 1 个字符和最后 1 个字符

# sed 's/.//1;s/.$//' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.13 删除每行的第 2 个字符和最后 1 个字符

# sed 's/.//2;s/.$//' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.14 删除所有行的数字和空格

# sed -r 's/[0-9]//g;s/^( )+//g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.15 删除 1 行不是最后 1 行包含 eternalcenter 的行

# sed '/eternalcenter/N;s/.*\n//' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.16 将所有的大写字母都添加括号

# sed 's/[A-Z]/(&)/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.17 在第 7 行和第 9 行前面添加 “#”

# sed '7,9s/^/#/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.18 删除第 1 个空格

# sed -r 's/( )(.*)/\2/'

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.19 在以打写字母开头,中间是小写字母,以数字结尾的行里在小写字母和数字之间插入 ok

# sed -r 's/^([A-Z]{1,})([a-z]{1,})([0-9]{1,})$/\1\2ok\3/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.20 在以打写字母开头,中间是小写字母,以数字结尾的行里在小写字母和数字之间插入 ok,并将数字替换到最前面

# sed -r 's/^([A-Z]{1,})([a-z]{1,})([0-9]{1,})$/\3 ok \1\2/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.21 删除 2022-01-01 字符里的横杠 “-”

# sed -r 's/([0-9]{1,})\-([0-9]{1,})\-([0-9]{1,})/\1\2\3/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.22 将日期的年月日以空格分开

# echo 20220222 | sed -r 's/(....)(..)(..)/\1 \2 \3/'

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.23 合并上下行

# sed '$!N;s/\n/ /' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.24 将以反斜杠号 “\” 结尾的行与下 1 行合并在一起并以空格进行分隔 (只合并一次)

# sed '/\\$/N;s/\\\n/ /' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.25 将以反斜杠号 “\” 结尾的行与下 1 行合并在一起并以空格进行分隔 (能合并多少次就合并多少次)

# sed -e :a -e '/\\$/N;s/\\\n/ /; ta' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.26 若某行以 = 开头则合并到上 1 行并将等于号 “=” 替换成空格

# sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D' num.txt 


补充:
1) 执行 :a 参数和 ta 参数,将从 :a 到 ta 之间的内容以后面的操作作为循环条件只要还能继续执行就一直循环,每次执行 $!N;s/\n=/ /,当不是最后 1 行时,将下 1 行的内容添加到本行后面,但是本行的内容和下 1 行的内容之间依旧存在分行符 “/n”,如果此时存在 \n=,则将其替换成空格,再将最后的结果以非标准输出的方式传输给 P 参数,执行 P 参数,将分行符 “/n” 之前的所有内容 (也就是最初此行的内容) 以非标准输出的形式显示,再将此时的所有内容以非标准输出的形式传输给 D 参数,执行 D 参数,删除前 1 行,也就是分行符 “/n” 之前的内容,如果删除后还有内容,则以此内容作为新的 1 行往下执行,否则跳过往下第 1 行接着执行往下第 2 行
2) 以此类推
3) 执行 s/^\n//g 删除所有行的换行符 “\n”
4) 这里的 test.txt 是要被 sed 操作的测试文件

7.27 行列转换,并且将第 1 行相同的列,行列转换以后合并,也就是行列转换以后没有第 1 列相互重复的行 (指定 1 列是 1 个 5 个字符长度的字节)

# awk '{for(i=1;i<=NF;i++){if(i in arr){arr[i]=arr[i]" "$i}else{arr[i]=$i}}}END{for(i=1;i<=NF;i++){print arr[i]}}' test.txt | sort | sed -e :a -e '$!N;/^\(.....\).*\n\1.*/s/^\(.*\)\(\n\)\(.....\)\(.*\)/\1\4/g; ta'

(补充:这里的 test.txt 是要被 awk 操作的测试文件)

7.28 行列转换,并且将第 1 行相同的列,行列转换以后合并,也就是行列转换以后没有第 1 列相互重复的行 (指定 1 列是以 .com 结尾)

# awk '{for(i=1;i<=NF;i++){if(i in arr){arr[i]=arr[i]" "$i}else{arr[i]=$i}}}END{for(i=1;i<=NF;i++){print arr[i]}}' test.txt | sort | sed -e :a -e '$!N;/^\(.*\.com\).*\n\1.*/s/^\(.*\)\(\n\)\(.*\.com\)\(.*\)/\1\4/g; ta'

(补充:这里的 test.txt 是要被 awk 操作的测试文件)

7.29 行列转换,并且将第 1 行相同的列,行列转换以后合并,也就是行列转换以后没有第 1 列相互重复的行 (指定 1 列是以空格 “ ” 结尾)

# > awk '{for(i=1;i<=NF;i++){if(i in arr){arr[i]=arr[i]" "$i}else{arr[i]=$i}}}END{for(i=1;i<=NF;i++){print arr[i]}}' test.txt | sort | sed -e :a -e '$!N;/^\(.*\ \).*\n\1.*/s/^\(.*\)\(\n\)\(.*\ \)\(.*\)/\1 \4/g; ta'

(补充:这里的 test.txt 是要被 awk 操作的测试文件)

内容八:sed 使用 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数第案例
8.1 sed 的工作原理

1) 从第 1 行开始 1 行 1 行地读取文件里的内容
2) 每读取 1 行就将内容存入到 pattern space (模型空间) 里面
3) 在 pattern space (模型空间) 中执行 sed 命令
4) 再显示 pattern space (模型空间) 中的内容然后将其清空
5) 之后重复以上操作再开始读取文件里的下 1 行
6) pattern space (模型空间) 里的内容可以存储到 hold space (保持空间) 里面


补充:
1) pattern space (模型空间) 相当于处理内容的流水线
2) hold space (保持空间) 相当于暂时存储内容的仓库

8.2 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的讲解
8.2.1 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的作用简介

1) g 将 hold space (保持空间) 中的内容拷贝到 pattern space (模型空间) 中,原来 pattern space (模型空间) 里的内容被清除
2) G 将 hold space (保持空间) 中的内容 append (添加) 到 pattern space (模型空间) 分行符 “/n” 后
3) h 将 pattern space (模型空间) 中的内容拷贝到 hold space (保持空间) 中,原来的 hold space (保持空间)里的内容被清除
4) H 将 pattern space (模型空间) 中的内容 append (添加) 到 hold space (保持空间) 分行符 “/n” 后
5) d 删除 pattern space (模型空间) 中的所有行,并执行下 1 行
6) D 删除 pattern space (模型空间) 中的第 1 行,也就是分行符 “/n” 之前的内容,如果删除后还有内容,则以此内容作为新的 1 行往下执行

8.2.2 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的功能示意图

P H     P H     P H
1    h  1 1  d    1

P H     P H     P H     P H
2 1  G  2 1  H  2 1  d    1
        1       1 2       2
                  1       1

P H     P H     P H
3 2  G  3 2  h  3 3
  1     2 1     2 2
        1       1 1

P H     P H
3 2  g  2 2
  1     1 1


补充:
1) 这里的 P 指的是 pattern space (模型空间)
2) 这里的 H 指的是 hold space (保持空间)
3) h 其实就是清空现在粘贴板里的内容然后重新复制
4) H 其实就是不清空现在粘贴板里的内容然后再再原来粘贴版的内容基础上再追加复制
5) g 其实就是替换粘贴
6) G 其实就是追加粘贴

8.3 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的使用案例
8.3.1 将第 1 行的数据添加到第 3 行后面

# sed -e '1h' -e '3G' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.2 将第 1 行的数据替换第 3 行

# sed -e '1h' -e '3g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.3 将第 1 行和第 2 行的数据添加到第 3 行后面

# sed -e '1h' -e '2H' -e '3G' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.4 将第 1 行和第 2 行的数据替换第 3 行

# sed -e '1h' -e '2H' -e '3g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.5 将第 1 个以 a 开头的行的数据添加到第 3 行后面

# sed -e '/^a/h' -e '3G' 1.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.6 将第 1 个和第 2 个以 a 开头的行的数据添加到第 3 行后面

# sed -e '/^a/h' -e'/^a/H' -e '3G' 1.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.7 将 eternalcenter 的 eternal 和 center 以空格分开

# echo "eternalcenter" | sed -r 'H;s/(.{7}).*/\1/;x;s/.*(.{6})$/\1/;x;G;s/\n/ /'

(
1) 执行 H 参数,将 pattern space (模型空间) 中的内容 append (添加) 到 hold space (保持空间) 分行符 “/n” 后,并将此时的 pattern space (模型空间) 传输给 s 参数
2) 执行 s/(.{7})./\1/,将 pattern space (模型空间) 中的内容只保留前 7 个字符,并将此时的 pattern space (模型空间) 传输给 x 参数 3) 执行 x 参数,将 hold space (保持空间) 和 pattern space (模型空间) 内容互换,,并将此时的 pattern space (模型空间) 传输给 s 参数 4) 执行 s/.(.{6})$/\1/,将 pattern space (模型空间) 中的内容只保留后 6 个字符,并将此时的 pattern space (模型空间) 传输给 x 参数
5) 执行 x 参数,将 hold space (保持空间) 和 pattern space (模型空间) 内容互换,,并将此时的 pattern space (模型空间) 传输给 G 参数
6) 执行 G 参数,将 hold space (保持空间) 中的内容 append (添加) 到 pattern space (模型空间) 分行符 “/n” 后,并将此时的 pattern space (模型空间) 传输给 s 参数
7) 执行 s/(.{7}).*/\1/,将 pattern space (模型空间) 中的内容删除换行符 “\n”
)

内容九:sed 一次匹配多个参数的案例

在 abc 和 bbb 那两行下面添加 1 行 eternalcenter

# sed -e "/abc/a eternalcenter" -e "/^bbb/a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容十:sed r 参数和 w 参数读取和写入文件
10.1 将 test2.txt 文件里的内容添加到 test1.txt 文件里内容的第3 行后面

# sed '3r test2.txt' test1.txt

(补充:这里的 test1.txt 和 test2.txt 是要被 sed 操作的测试文件)

10.2 将 test1.txt 文件里内容的第三行保存到 test2.txt 中

# sed '3w test2.txt' test1.txt

(补充:这里的 test1.txt 和 test2.txt 是要被 sed 操作的测试文件)

内容十一:sed q 参数退出当前执行的内容
11.1 执行完第 5 行后退出

# sed '5 q' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

11.2 执行完包含 eternalcenter 的行后退出

# sed '/eternalcenter/ q' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

11.3 执行完第 3 行后退出,并将退出代码设置为 3

# sed '3 q 3' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容十二:sed b 参数和 t 参数设置标签分支
12.1 如果某行不包含 eternalcenter 则将此行中内容的 0 换成 1,否则将此行中内容的 0 换成 2

# sed '{/eternalcenter/b lable;s/0/1/;:lable}' test.txt


补充:
1) 在这里 lable 是标签
2) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed '/eternalcenter/ba;s/0/1/;b;:a' test.txt


补充:
1) 在这里 a 是标签
2) 这里的 test.txt 是要被 sed 操作的测试文件

12.2 如果某行包含 eternalcenter 则将此行中内容的 0 换成 1,否则将此行中内容的 0 换成 2

# sed '/eternalcenter/s/0/1/;t;s/0/2/' test.txt


补充:
1) 在这里的标签省略了,所以标签分支会一直到头部
2) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed -e :a -e '/eternalcenter/s/0/1/;ta;s/0/2/' test.txt


补充:
1) 在这里 a 是标签
2) 这里的 test.txt 是要被 sed 操作的测试文件

[命令] Linux 命令 grep (显示文本的行)

案例一:grep 使用正则表达式匹配

# grep -E '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行为例)

案例二:grep 显示行号
2.1 显示某些关键字所在行行号

# egrep -n '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并显示行号为例)

2.2 显示哪些行号是空行

# egrep -n ^$ /etc/resolv.conf

(补充:这里以匹配 /etc/resolv.conf 里的空行并显示行号为例)

案例三:grep 取反匹配
3.1 取反不匹配某些关键字

# egrep -v '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里不含有 IP 地址的行并显示行号为例)

3.2 取反不显示空行

# egrep -v ^$ /etc/resolve.conf

(补充:这里以匹配 /etc/resolve.conf 文件里不为空的行为例)

3.3 取反不显示以井号 “#” 开头的行

# grep '^[^#]' /etc/resolve.conf

(补充:这里以匹配 /etc/resolve.conf 文件里不以井号 “#” 开头的行为例)

3.4 取反不显示以井号 “#” 或空格 “ ” 开头的行

# grep '^[^#| ]' /etc/resolve.conf

(补充:这里以匹配 /etc/resolve.conf 文件里不以井号 “#” 和空格 “ ” 开头的行为例)

案例四:grep 只显示匹配的部分

# egrep -o '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 里的 IP 地址为例)

(注意:这里匹配后只显示 IP 地址,而不显示 IP 地址所在行里的其他内容)

案例五:grep 匹配时忽略大小写

# egrep -i '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并忽略大小写为例)

案例六:grep 统计匹配成功次数

# egrep -c '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行的数量为例)

案例七:grep 将匹配成功的部分自动添加颜色

# egrep --color=auto '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并自动添加颜色为例)

案例八:grep 将匹配成功的部分自动取消颜色

# egrep --color=no '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192  

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并取消自动添加颜色为例)

案例九:grep 一次匹配多个参数

# grep -e root -e zhumingyu /etc/passwd

(补充:这里以匹配 /etc/passwd 文件中包含 root 或 zhumingyu 的行为例)

案例十:显示匹配内容附近的内容
10.1 显示匹配内容的前 10 行

# grep -a 10 eternalcenter test.txt

(补充:这里以匹配 test.txt 文件中包含 eternalcenter 的行并显示其前 10 行为例)

10.2 显示匹配内容的后 10 行

# grep -b 10 eternalcenter test.txt

(补充:这里以匹配 test.txt 文件中包含 eternalcenter 的行并显示其后 10 行为例)

10.3 显示匹配内容的前后 10 行

# grep -a -b 10 eternalcenter test.txt

(补充:这里以匹配 test.txt 文件中包含 eternalcenter 的行并显示其前后 10 行为例)

[排错] 解决 Linux 删除数据后依旧无法释放空间

解决方法:

步骤一:理解出现问题的原因

当删除某些数据时,此数据正在被某个进程使用,则这些数据需要 kill 掉这个进程后才能被删除掉

步骤二:显示目录的使用状态

# df -h

(注意:如果出现已用存储加剩余存储小于总存储的情况,就代表出现了被删除的数据正在被进程使用的情况 )

步骤三:显示对应目录里所有一级子目录的大小

# du -ah --max-depth=1

步骤四:显示是否有进程在使用正在被删除的数据

# lsof | grep delete

步骤五:kill 这些进程以让这些数据被成功删除

# kill -9 `lsof | grep delete | awk '{print $2}'` 

(注意:kill 进程有一定的风险,请小心执行)

[排错] 解决 openSUSE & SUSE 通过 YaST 配置 IP 地址时报错 “Network is currently handled by NetworkManager”

报错代码:

Network is currently handled by NetworkManager

解决方法:

步骤一:报错现象和原因分析
1.1 报错现象

通过 yast 给 openSUSE 和 SUSE 配置 IP 地址时可能会出现以下报错

(图:1)

1.2 原因分析

如果是带桌面安装 openSUSE 和 SUSE ,系统则会默认使用 NetworkManager 管理网络,这样会导致 yast 无法配置 IP 地址

步骤二:排错
2.1 取消开机自启 NetworkManager

# systemctl disable NetworkManager

2.2 停止 NetworkManager 服务

# systemctl stop NetworkManager

2.3 在 yast 中将 General Network Settings 从 NetworkManager Service 换成 Wicked Service
2.3.1 进入 yast

# yast

2.3.2 进入 System 下面的 Network Settings

2.3.3 在 Global Options 选项中将 General Network Settings 从 NetworkManager Service 换成 Wicked Service

(图:2)