0%

sort 命令详解:文本排序与数据整理的实用工具

sort 是 Linux 系统中用于对文本内容进行排序的核心命令,它以行为单位对输入数据进行排序,并支持按列、数值、月份等多种方式排序,是处理日志、表格数据、配置文件等的重要工具。本文将详细讲解 sort 命令的选项、用法及实战案例。

sort 基本用法与排序规则

基本语法

1
sort [选项] [文件...]
  • 若不指定文件,sort 从标准输入(管道或键盘)读取数据。
  • 默认排序规则:按字符的 ASCII 码值从小到大排序(字典序)。

基础示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 示例文件:nums.txt
# 3
# 1
# 5
# 2


# 对文件内容排序(默认升序)
sort nums.txt
# 输出:
# 1
# 2
# 3
# 5

# 对管道输入排序(如列出当前目录并排序)
ls | sort
阅读全文 »

awk 命令详解:文本处理与数据提取的强大工具

awk 是 Linux 系统中处理文本数据的强大工具,尤其擅长按字段分割、提取关键信息、统计分析等任务。它将输入视为 “记录(行)” 和 “字段(列)” 的集合,通过 “模式 - 动作” 对实现灵活的文本处理。本文将系统讲解 awk 的核心用法、内建变量、高级特性及实战案例。

awk 基本工作原理与语法

核心概念

  • 记录(Record):默认以换行符(\n)分隔,即一行为一条记录。
  • 字段(Field):默认以空格或制表符分隔,每条记录可拆分为多个字段($1 表示第 1 个字段,$2 第 2 个,$0 表示整行)。
  • 模式 - 动作对awk 程序由 pattern { action } 组成,当记录匹配 pattern 时,执行 action(动作)。

基本语法

1
awk [选项] 'pattern1 { action1 } pattern2 { action2 } ...' 输入文件
常用选项
  • -F fs:指定字段分隔符(fs 可以是字符、正则表达式),默认是空格 / 制表符。
  • -v var=value:在 awk 程序中定义变量(传递外部值到 awk)。
  • -f file:从文件 file 中读取 awk 程序(适合复杂脚本)。

基础示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 示例文件:data.txt
# name age gender
# Alice 25 female
# Bob 30 male
# Charlie 28 male


# 打印所有行($0 表示整行)
awk '{print $0}' data.txt

# 打印第1个和第3个字段(姓名和性别)
awk '{print $1, $3}' data.txt

# 仅打印第2行(NR 是内建变量,表示行号)
awk 'NR==2 {print $0}' data.txt

# 按冒号分隔字段(如 /etc/passwd),打印用户名(第1列)和 shell(第7列)
awk -F: '{print $1, $7}' /etc/passwd
阅读全文 »

Linux 中 Shell 的类型与查看方法

在 Linux 系统中,Shell 作为用户与内核交互的接口,提供了多种实现(如 bash、sh、zsh 等)。了解系统支持的 Shell 类型及默认 Shell,对脚本编写和环境配置至关重要。

Shell 解释器的指定:#! 声明

Shell 脚本第一行的 #!/bin/bash 称为释伴(shebang),其作用是告诉系统:使用 /bin/bash 这个解释器来执行脚本。

  • 原理#! 是一个特殊标记,其后跟随的路径指向具体的 Shell 解释器(或其他脚本解释器,如 /usr/bin/python)。

  • 示例:

    1
    2
    3
    #!/bin/sh      # 使用 sh 解释器
    #!/usr/bin/zsh # 使用 zsh 解释器
    #!/usr/bin/env bash # 更灵活的写法,从环境变量中查找 bash
  • 注意:若脚本未指定 #!,系统会默认使用当前用户的默认 Shell 执行。

查看系统支持的 Shell 类型

Linux 系统中,所有支持的 Shell 类型都记录在 /etc/shells 文件中,通过以下命令可查看:

1
cat /etc/shells

输出示例

1
2
3
4
5
6
7
8
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/zsh
/usr/bin/zsh
/bin/csh
/usr/bin/csh
阅读全文 »

保持 SSH 连接不中断的完整方案:客户端与服务端配置

使用 SSH 连接服务器时,若长时间无操作,连接常因超时被自动断开,需重新登录,影响工作效率。本文将从客户端(Linux/Mac/Windows)和服务端两个维度,详细介绍如何通过配置保持 SSH 连接长期稳定。

客户端配置(主动发送保活信号)

客户端配置的核心是定期向服务器发送 “保活消息”,避免连接因超时被断开。

Linux 或 Mac 客户端(终端直接连接)

(1)全局配置(对所有服务器生效)
1
2
# 编辑 SSH 客户端配置文件
vi ~/.ssh/config

添加以下内容:

1
2
3
4
5
6
# 对所有服务器生效(* 表示通配符)
Host *
# 每 120 秒向服务器发送一次保活消息(检查连接是否存活)
ServerAliveInterval 120
# 最多允许 30 次未收到服务器响应(超过则断开连接)
ServerAliveCountMax 30
(2)局部配置(仅对特定服务器生效)

若只需对某台服务器保持连接,可指定服务器 IP 或域名:

阅读全文 »

Linux 内存映射(mmap):将文件直接映射到内存的高效 IO 技术

内存映射(Memory Mapping)是 Linux 内核提供的一种高效文件访问机制,通过将磁盘文件的部分或全部内容映射到进程的地址空间,使进程可以像访问内存一样读写文件,无需通过传统的 read()/write() 系统调用。这种技术在高性能 IO 场景(如数据库、大文件处理)中被广泛应用。

内存映射的基本原理

核心思想

内存映射通过 mmap() 系统调用建立进程地址空间的一块区域磁盘文件的关联:

  • 内核会在进程的虚拟地址空间中分配一段连续的地址范围(称为 “映射区”);
  • 这段地址不直接对应物理内存,而是与目标文件的磁盘区块建立映射关系;
  • 当进程访问映射区时,内核会通过页表将访问转换为对文件的读写操作(按需加载数据到物理内存,即 “页缓存” 机制)。

与传统 IO 的区别

传统文件访问(read()/write())需要经过 “用户态缓冲区 ↔ 内核页缓存 ↔ 磁盘” 的两次数据拷贝,而内存映射简化了流程:

操作方式 数据路径 优势场景
传统 IO 用户缓冲区 ↔ 内核页缓存 ↔ 磁盘 小文件、随机读写、需精确控制 IO
内存映射(mmap) 进程地址空间(映射区) ↔ 内核页缓存 ↔ 磁盘 大文件、顺序读写、频繁访问

核心优势:减少用户态与内核态之间的数据拷贝,提升大文件访问效率。

mmap () 系统调用详解

函数原型

1
2
3
#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
参数说明:
  • addr:指定映射区的起始地址(通常设为 NULL,由内核自动分配);

  • length:映射的文件长度(字节数,必须 ≥ 0);

  • prot:映射区的保护权限(内存访问权限):

  • PROT_READ:可读;

    • PROT_WRITE:可写;
  • PROT_EXEC:可执行;

    • PROT_NONE:无权限。
  • flags:映射类型和行为(关键参数):

    • MAP_SHARED:映射区的修改会同步到文件(进程间共享修改);
    • MAP_PRIVATE:映射区的修改是私有的(Copy-on-Write,不影响原文件);
    • MAP_ANONYMOUS:匿名映射(无关联文件,用于进程间共享内存)。
  • fd:待映射的文件描述符(需先通过 open() 打开);

  • offset:文件映射的起始偏移量(必须是页大小的整数倍,通常为 0)。

返回值:

  • 成功:返回映射区的起始地址(void *);
  • 失败:返回 MAP_FAILED(void *)-1),并设置 errno

配套函数:munmap ()

用于解除内存映射,释放映射区:

1
int munmap(void *addr, size_t length);
  • addrmmap() 返回的映射区起始地址;
  • length:映射区的长度(需与 mmap() 一致);
  • 返回值:0 表示成功,-1 表示失败。

内存映射的关键特性

两种映射模式(flags 参数)

(1)MAP_SHARED(共享映射)
  • 进程对映射区的修改会同步到磁盘文件,且其他映射该文件的进程可见;
  • 适用于需要持久化修改或多进程协作的场景(如共享日志文件)。
(2)MAP_PRIVATE(私有映射)
  • 进程对映射区的修改不会同步到原文件,也不会被其他进程看到;
  • 内核采用 “写时复制(Copy-on-Write)” 机制:仅当进程修改映射区时,才复制物理页,避免影响其他进程;
  • 适用于临时读写文件(如读取配置文件并临时修改)。

匿名映射(MAP_ANONYMOUS

  • 无需关联文件(fd 设为 -1,offset 忽略),映射区的内容在进程退出后消失;

  • 常用于进程间共享内存(结合 fork() 或线程),或需要大块内存临时存储数据的场景;

  • 示例:

    1
    2
    // 分配 4KB 匿名共享内存(可被子进程继承)
    void *addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

页缓存与延迟写入

内存映射依赖内核的页缓存(Page Cache) 机制:

  • 首次访问映射区时,内核会将文件内容从磁盘加载到物理内存(页缓存);

  • 进程修改映射区时,内核先更新页缓存,再通过 “延迟写回” 机制异步将脏页(修改过的页)写入磁盘(可通过 msync() 强制同步);

  • msync()函数:手动同步映射区与文件,确保修改持久化:

    1
    2
    int msync(void *addr, size_t length, int flags);
    // flags:MS_SYNC(同步等待写完成)、MS_ASYNC(异步写)、MS_INVALIDATE(丢弃缓存,重新从文件加载)

使用示例:通过 mmap 读写文件

读取文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

int main() {
int fd = open("test.txt", O_RDONLY); // 打开文件
struct stat st;
fstat(fd, &st); // 获取文件大小

// 映射文件(只读,共享模式)
char *addr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
perror("mmap failed");
return 1;
}

// 像访问内存一样读取文件内容
printf("File content: %s\n", addr);

// 解除映射并关闭文件
munmap(addr, st.st_size);
close(fd);
return 0;
}

写入文件内容(共享映射)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>

int main() {
int fd = open("test.txt", O_RDWR | O_CREAT, 0644); // 读写方式打开
ftruncate(fd, 1024); // 确保文件大小足够(如创建新文件)

// 映射文件(可读写,共享模式)
char *addr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
perror("mmap failed");
return 1;
}

// 写入数据(直接修改内存)
strcpy(addr, "Hello, mmap!");

// 强制同步到磁盘
msync(addr, 1024, MS_SYNC);

munmap(addr, 1024);
close(fd);
return 0;
}

注意事项与限制

  1. 文件大小与映射长度
    • length 不能超过文件大小(除非文件可扩展,且以 O_RDWR 打开);
    • 映射超过文件大小的部分写入时,可能导致文件扩展(取决于文件系统支持)。
  2. 对齐要求
    • offset 必须是系统页大小(通常 4KB)的整数倍,否则 mmap() 失败(EINVAL)。
  3. 文件描述符关闭
    • 映射建立后,可关闭 fd(映射仍有效),但建议保持打开直至映射解除(便于错误排查)。
  4. 信号安全
    • mmap()munmap() 不是异步信号安全的,避免在信号处理函数中调用。
  5. 性能陷阱
    • 小文件使用 mmap() 可能因页缓存 overhead 导致性能不如传统 IO;
    • 频繁修改小区域时,MAP_PRIVATE 的写时复制可能带来额外开销。

应用场景

内存映射适用于以下场景:

  • 大文件处理:如数据库表文件、日志文件,避免频繁 read()/write() 拷贝;
  • 进程间共享内存:通过 MAP_SHARED 或匿名映射实现高效通信(比管道、消息队列快);
  • 动态加载代码:如操作系统加载可执行文件到内存执行(映射二进制文件并设置 PROT_EXEC);
  • 零拷贝 IO:结合网络编程(如 sendfile()),实现文件数据从页缓存直接发送到网络,避免用户态拷贝