AWK系统学习指南:从文本处理到数据分析的终极武器 介绍

news2025/3/13 7:18:36

 

目录

一、AWK核心设计哲学解析

1.1 记录与字段的原子模型

1.2 模式-动作范式

二、AWK编程语言深度解析

2.1 控制结构

说明:

2.2 关联数组

代码说明:

示例输入和输出:

注意事项:

2.3 内置函数库

三、高级应用技巧

3.1 多文件处理

代码说明:

示例输入和输出:

注意事项:

3.2 进程间通信

代码说明:

示例输出:

改进版本(支持毫秒):

3.3 模块化编程

代码说明:

示例:

注意事项:

改进版本(增加错误处理):

总结:

四、性能优化实践

4.1 正则表达式优化

脚本解释:

示例输入和输出:

注意事项:

4.2 内存管理

4.3 并行处理

命令解释:

附录:AWK版本特性对比


一、AWK核心设计哲学解析

1.1 记录与字段的原子模型

AWK将输入数据视为由记录(Record)和字段(Field)构成的二维结构:

  • 记录默认以换行符分隔(RS变量控制)
  • 字段默认以空白字符分隔(FS变量控制)
  • 内置变量:
    • $0:完整记录
    • $1~$n:第1到第n个字段
    • NF:当前记录字段总数
    • NR:已处理记录总数

# 示例:显示文件每行的字段数

{print NR, NF}

1.2 模式-动作范式

AWK程序由模式(Pattern)和动作(Action)的配对组成:

pattern { action }
  • BEGIN模式:程序开始前执行
  • END模式:所有记录处理完毕后执行
  • 正则表达式模式:/regex/
  • 范围模式:pattern1, pattern2
# 示例:统计/etc/passwd中普通用户数量 
BEGIN {count=0} 
$3 >= 1000 && $3 < 60000 {count++} 
END {
    print "普通用户数量:", count
}

二、AWK编程语言深度解析

2.1 控制结构

说明:

  1. 条件判断ifelse ifelse 语句的代码块都进行了缩进,使结构更清晰。

  2. 循环结构

    • for 循环的初始条件、循环条件和更新部分都放在一行,代码块进行了缩进。

    • while 和 do-while 循环的代码块也进行了缩进,确保可读性。

# 条件判断
if (condition) {
    statements
} else if (condition) {
    statements
} else {
    statements
}

# 循环结构
for (i = 0; i < 10; i++) {
    print(i)
}

while (condition) {
    statements
}

do {
    statements
} while (condition)

2.2 关联数组

AWK的数组本质上是键值对的哈希表:

# 统计词频 
{
    for (i = 1; i <= NF; i++) {
        words[$i]++
    }
}

END {
    for (w in words) {
        print w, words[w] | "sort -nrk2"
    }
}

代码说明:

  1. 主循环部分

    • NF 是 AWK 的内置变量,表示当前行的字段数(即单词数)。

    • for (i = 1; i <= NF; i++) 遍历每一行的每个单词。

    • words[$i]++ 将每个单词作为键,值是其出现的次数,存入关联数组 words 中。

  2. END 块

    • END 是 AWK 的特殊模式,表示在处理完所有输入行后执行。

    • for (w in words) 遍历 words 数组中的每个单词。

    • print w, words[w] 输出单词及其出现次数。

    • | "sort -nrk2" 将输出通过管道传递给 sort 命令,按第二列(出现次数)数值从高到低排序。

示例输入和输出:

假设输入文件内容如下:

hello world
hello awk
world is great

运行该 AWK 脚本后,输出结果为:

hello 2
world 2
awk 1
is 1
great 1

注意事项:

  • 这段代码假设输入是以空格分隔的文本。

  • 如果需要忽略大小写,可以在 words[$i]++ 之前将单词转换为小写,例如 words[tolower($i)]++

  • 如果需要去除标点符号,可以在处理单词时进行额外的过滤。

2.3 内置函数库

函数类别典型函数功能说明
字符串处理length(), substr(), split()字符串操作
数学运算sin(), log(), int()数学计算
时间处理systime(), strftime()时间转换
I/O操作getline(), system()输入输出控制
类型转换strtonum(), tolower()数据类型转换

三、高级应用技巧

3.1 多文件处理

# 处理多个文件时自动重置行号
FILENAME != prevfile {
    prevfile = FILENAME
    FNR = 0
}

{
    print FILENAME, FNR, $0
}

代码说明:

  1. FILENAME != prevfile 条件

    • FILENAME 是 AWK 的内置变量,表示当前正在处理的文件名。

    • prevfile 是一个自定义变量,用于存储上一个处理的文件名。

    • 当 FILENAME 不等于 prevfile 时,表示切换到新文件,需要重置行号。

  2. 重置行号

    • prevfile = FILENAME:更新 prevfile 为当前文件名。

    • FNR = 0:将 FNR(当前文件的行号)重置为 0。注意,FNR 会在每次读取新行时自动递增,因此这里设置为 0 是为了让下一行的 FNR 从 1 开始。

  3. 主处理块

    • print FILENAME, FNR, $0:输出当前文件名、行号和当前行的内容。

示例输入和输出:

假设有两个文件:

文件 file1.txt

Hello
World

文件 file2.txt

AWK
is
great

运行该 AWK 脚本后,输出结果为:

file1.txt 1 Hello
file1.txt 2 World
file2.txt 1 AWK
file2.txt 2 is
file2.txt 3 great

注意事项:

  • 这段代码适用于处理多个文件,且需要在每个文件的行号从 1 开始计数时使用。

  • 如果不需要重置行号,可以直接使用 NR(全局行号)而不是 FNR

  • 如果文件名中包含空格,建议将 FILENAME 用引号括起来,例如 print "\"" FILENAME "\"", FNR, $0

3.2 进程间通信

# 调用系统命令处理数据
BEGIN {
    cmd = "date +%s"
    cmd | getline timestamp
    close(cmd)
    print "当前时间戳:", timestamp
}

代码说明:

  1. BEGIN 块

    • BEGIN 是 AWK 的特殊模式,表示在处理任何输入行之前执行。

    • 在这里,BEGIN 块用于初始化操作。

  2. 获取时间戳

    • cmd = "date +%s":定义一个命令字符串 cmd,用于调用系统命令 date +%s,该命令会输出当前的时间戳。

    • cmd | getline timestamp:通过管道将命令 cmd 的输出传递给 getline,并将结果存储在变量 timestamp 中。

    • close(cmd):关闭命令管道,释放资源。

  3. 输出时间戳

    • print "当前时间戳:", timestamp:输出当前时间戳。

示例输出:

运行该 AWK 脚本后,输出结果类似于:

当前时间戳: 1698765432

注意事项:

  1. 系统依赖

    • 这段代码依赖于系统的 date 命令,因此在 Unix/Linux 系统上可以正常运行,但在 Windows 系统上可能无法直接运行。

    • 如果系统中没有 date 命令,或者 date +%s 不支持,脚本会报错。

  2. 时间戳格式

    • date +%s 输出的时间戳是以秒为单位的整数。

    • 如果需要毫秒级别的时间戳,可以使用 date +%s%3N(部分系统支持)。

  3. close(cmd) 的作用

    • close(cmd) 用于关闭命令管道,避免资源泄漏。如果省略这一步,可能会导致文件描述符耗尽等问题。

改进版本(支持毫秒):

如果需要更高精度的时间戳(毫秒),可以修改命令如下:

BEGIN {
    cmd = "date +%s%3N"  # 获取秒和毫秒
    cmd | getline timestamp
    close(cmd)
    print "当前时间戳(毫秒):", timestamp
}

3.3 模块化编程

# 包含外部函数库
@include "awklib.awk" { 
    print format_date($1)
}

代码说明:

  1. @include "awklib.awk"

    • @include 是 GNU AWK 的扩展功能,用于引入外部 AWK 脚本文件。

    • 这里引入了名为 awklib.awk 的库文件,假设该文件中定义了 format_date 函数。

  2. 主处理块

    • { print format_date($1) }:对每一行的第一个字段($1)调用 format_date 函数,并输出格式化后的日期。 

示例:

假设 awklib.awk 文件中定义了以下函数:

# awklib.awk
function format_date(timestamp) {
    return strftime("%Y-%m-%d %H:%M:%S", timestamp)
}

输入文件内容如下:

1698765432
1698841832

运行该 AWK 脚本后,输出结果为:

2023-10-31 12:37:12
2023-11-01 10:30:32

注意事项:

  1. @include 的兼容性

    • @include 是 GNU AWK 的扩展功能,仅在 GNU AWK(gawk)中支持。如果使用其他 AWK 实现(如 mawk 或 nawk),可能需要手动合并代码或使用其他方式引入库文件。

  2. format_date 函数的实现

    • 假设 awklib.awk 文件中定义了 format_date 函数。如果该函数未定义或实现不正确,脚本会报错。

    • 如果 format_date 函数未定义,可以在脚本中自行实现,例如:

      function format_date(timestamp) {
          return strftime("%Y-%m-%d %H:%M:%S", timestamp)
      }
  3. 输入数据的格式

    • 假设输入文件的每一行第一个字段是一个有效的时间戳(整数)。如果输入数据格式不正确,可能会导致错误。

改进版本(增加错误处理):

如果输入数据可能包含无效的时间戳,可以增加错误处理逻辑:

@include "awklib.awk"

{
    if ($1 ~ /^[0-9]+$/) {
        print format_date($1)
    } else {
        print "错误: 无效的时间戳", $1
    }
}

总结:

  • 这段代码的核心是通过 @include 引入外部库,并调用库中的函数处理数据。

  • 如果 awklib.awk 文件或 format_date 函数未定义,需要确保其存在并正确实现。

  • 如果输入数据格式不确定,建议增加错误处理逻辑。

四、性能优化实践

4.1 正则表达式优化

# 邮箱验证脚本详解:避免重复编译正则表达式
BEGIN {
    email_regex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" 
}
$0 ~ email_regex {
    print "有效邮箱:", $0
}

脚本解释:

  1. BEGIN 块

    • BEGIN { email_regex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" }

    • 在脚本开始执行之前,定义了一个正则表达式 email_regex,用于匹配有效的电子邮件地址。

    • 正则表达式的含义:

      • ^[a-zA-Z0-9._%+-]+:匹配邮箱的用户名部分,允许字母、数字、点(.)、下划线(_)、百分号(%)、加号(+)和减号(-)。

      • @:匹配邮箱地址中的 @ 符号。

      • [a-zA-Z0-9.-]+:匹配域名部分,允许字母、数字、点(.)和减号(-)。

      • \.[a-zA-Z]{2,}$:匹配顶级域名(如 .com.org),要求至少两个字母。

  2. 主块

    • $0 ~ email_regex { print "有效邮箱:", $0 }

    • 对输入的每一行($0 表示整行内容)进行匹配。

    • 如果当前行符合 email_regex 正则表达式,则打印 "有效邮箱:" 和该行的内容。

示例输入和输出:

假设输入文件 emails.txt 内容如下:

test@example.com
invalid-email
user.name+tag+sorting@example.com
user@sub.example.com
not-an-email

运行以下命令:

awk -f script.awk emails.txt

输出结果为:

有效邮箱: test@example.com
有效邮箱: user.name+tag+sorting@example.com
有效邮箱: user@sub.example.com

注意事项:

  1. 正则表达式可能无法覆盖所有合法的电子邮件地址(例如包含国际化域名的邮箱)。

  2. 如果你需要更复杂的邮箱验证,建议使用专门的库或工具(如 Python 的 email-validator 库)。

  3. 如果输入文件中有空行或格式不正确的行,它们会被忽略。 

4.2 内存管理

# 及时清空大数组

{
    big_array[NR] = $0
    if (NR % 10000 == 0) {
        process_data(big_array)
        delete big_array
    }
}
  1. 数据缓存阶段:将每行内容存入数组big_array,使用行号NR作为索引
  2. 批处理触发条件:当处理行数是10000的倍数时(第10000、20000...行)
  3. 数据处理阶段:调用process_data处理累计的10000行数据
  4. 内存清理:使用delete清空数组释放内存

4.3 并行处理

# 使用GNU Parallel配合AWK 
find . -name "*.log" -exec cat {} + | parallel --pipe awk '/ERROR/{count++} END{print count}' | awk '{sum+=$1} END{print sum}'
  • 命令解释:

  • find . -name "*.log"

    • 从当前目录(.)递归查找所有以 .log 结尾的文件。

  • parallel --pipe

    • --pipe 选项将输入(即 find 找到的文件内容)分块传递给后续命令(这里是 awk)。

    • GNU Parallel 会将输入分成多个块,并在多个 CPU 核心上并行处理这些块。

  • awk '/ERROR/{count++} END{print count}'

    • awk 脚本的作用是:

      • 对每一行匹配 /ERROR/,如果匹配成功,则计数器 count 加 1。

      • 在处理完所有行后,输出 count 的值。

附录:AWK版本特性对比

特性AWKNawkGawkMawk
正则表达式引擎BREEREEREDFA
多维数组支持×××
TCP/IP网络编程×××
性能(百万行/秒)2.13.41.84.7
Unicode支持×××

掌握AWK需要理解其设计哲学,通过大量实践积累模式。建议从简单文本处理入手,逐步过渡到复杂的数据分析场景。现代Gawk版本已支持网络编程和数据库访问,可以构建完整的CLI数据处理管道。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2295133.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

250207-MacOS修改Ollama模型下载及运行的路径

在 macOS 上&#xff0c;Ollama 默认将模型存储在 ~/.ollama/models 目录。如果您希望更改模型的存储路径&#xff0c;可以通过设置环境变量 OLLAMA_MODELS 来实现。具体步骤如下&#xff1a; 选择新的模型存储目录&#xff1a;首先&#xff0c;确定您希望存储模型的目标目录路…

半导体行业跨网文件交换系统

在当今这个数字化转型的时代&#xff0c;半导体行业作为技术密集型产业&#xff0c;正面临着前所未有的信息安全挑战。随着企业内外网隔离措施的加强&#xff0c;如何实现既安全又高效的跨网文件交换&#xff0c;成为了众多半导体企业的一大难题。 特别是在研发和生产过程中产生…

使用GD32F470的硬件SPI读写W25Q64

代码简单改下引脚定义便可以使用&#xff01; 使用的单片机具体型号&#xff1a;GD32F470ZGT6 简单介绍下W25Q64&#xff1a; /* W25Q64 性能参数 */ /* 容量&#xff1a;8MByte 64Mbit */ /* 有128个块&#xff0c;每个块有64KByte */ /* 每个块有16个扇区&#xff0c;每个…

02为什么 OD门和 OC门输出必须加上拉电阻?

为什么 OD&#xff08;开漏&#xff09;门和 OC&#xff08;开集&#xff09;门输出必须加上拉电阻&#xff1f; 1、首先一点&#xff0c;知道OD是说的MOS管&#xff0c;OC是说的三极管&#xff0c;二者的区别与联系大家应该都懂。 2、以OC门举例&#xff0c;芯片的OC门内部结…

AI方案调研与实践 (不定期补充)

目录 说明 1. AI云主机准备 1.1 Ollama配置 设置模型保存路径 配置模型驻留内存时间 查看GPU状况命令: nvidia-smi 2. Deepseek 2.1 安装与使用 3. LobeChat配置 参考 说明 调研并实例化各种AI方案&#xff0c;探索训练/使用方式的最佳实践。 1. AI云主机准备 可以去一…

人工智能大模型之模型蒸馏与知识蒸馏

一、背景介绍 随着人工智能技术的不断发展&#xff0c;大模型在各个领域的应用也越来越广泛。模型蒸馏&#xff08;Model Distillation&#xff09;和知识蒸馏&#xff08;Knowledge Distillation&#xff09;是两种非常重要的模型压缩技术&#xff0c;它们可以帮助我们将大型…

[手机Linux] onepluse6T 系统重新分区

一&#xff0c;刷入TWRP 1. 电脑下载 Fastboot 工具&#xff08;解压备用&#xff09;和对应机型 TWRP&#xff08;.img 后缀文件&#xff0c;将其放入前面解压的文件夹里&#xff09; 或者直接这里下载:TWRP 2. 将手机关机&#xff0c;长按音量上和下键 开机键 进入 fastbo…

k8s部署elasticsearch

前置环境&#xff1a;已部署k8s集群&#xff0c;ip地址为 192.168.10.1~192.168.10.5&#xff0c;总共5台机器。 1. 创建provisioner制备器&#xff08;如果已存在&#xff0c;则不需要&#xff09; 制备器的具体部署方式&#xff0c;参考我之前的文章&#xff1a;k8s部署rab…

本地部署DeepSeek

下载Docker Docker Desktop: The #1 Containerization Tool for Developers | Docker 下载安装ollama Download Ollama on macOS 下载完成后解压运行 终端输入 Ollama --version 输出对应版本号即为下载成功 如果没有弹出上述图片&#xff0c;浏览器输入http://localhos…

21.[前端开发]Day21-HTML5新增内容-CSS函数-BFC-媒体查询

王者荣耀-网页缩小的问题处理 为什么会产生这个问题&#xff1f;怎么去解决 可以给body设置最小宽度 1 HTML5新增元素 HTML5语义化元素 HTML5其他新增元素 2 Video、Audio元素 HTML5新增元素 - video video支持的视频格式 video的兼容性写法 HTML5新增元素 - audio audio…

nbmade-boot调用deepseek的api过程与显示

希望大家一起能参与我的新开源项目nbmade-boot: 宁波智能制造低代码实训平台 下面简单介绍调用最近大红的AI &#xff1a;deepseek的api过程与显示&#xff0c;包括前后端代码与效果图 一、后端代码 1、几个基础的java类 DeepSeekRequest .java package com.nbcio.demo.do…

Linux:安装 node 及 nvm node 版本管理工具(ubuntu )

目录 方法一&#xff1a;手动下载安装文件安装方法二&#xff1a;curl安装 方法一&#xff1a;手动下载安装文件安装 git clone 远程镜像 git clone https://gitee.com/mirrors/nvm安装 nvm bash install.sh刷新配置&#xff0c;使配置在终端生效 // 方法 1 source /root/.…

【多线程-第三天-NSOperation和GCD的区别 Objective-C语言】

一、我们来看NSOperation和GCD的区别 1.我们来对比一下,NSOperation和GCD, 那这个代码,我们都写过了, 我们来看一下它们的特点啊,首先来看GCD, 1)GCD是C语言的框架,是iOS4.0之后推出的,并且它的特点是,针对多核做了优化,可以充分利用CPU的多核,OK,这是GCD, 2…

【医院运营统计专题】2.运营统计:医院管理的“智慧大脑”

医院成本核算、绩效管理、运营统计、内部控制、管理会计专题索引 引言 在当今医疗行业快速发展的背景下,医院运营管理的科学性和有效性成为了决定医院竞争力和可持续发展能力的关键因素。运营统计作为医院管理的重要工具,通过对医院各类数据的收集、整理、分析和解读,为医…

Ollama 部署 DeepSeek-R1 及Open-WebUI

Ollama 部署 DeepSeek-R1 及Open-WebUI 文章目录 Ollama 部署 DeepSeek-R1 及Open-WebUI〇、说明为什么使用本方案 一、 安装Ollama1、主要特点&#xff1a;2、安装3、验证 二、Ollama 部署 DeepSeek1、部署2、模型选用3、Ollama 常用命令4、Ollama模型默认存储路径 安装open-w…

Vite 打包原理

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【大模型】Ubuntu下安装ollama,DeepSseek-R1:32b的本地部署和运行

1 ollama 的安装与设置 ollama官网链接&#xff1a;https://ollama.com/ 在左上角的【Models】中展示了ollama支持的模型在正中间的【Download】中课可以下载支持平台中的安装包。   其安装和模型路径配置操作流程如下&#xff1a; ollama的安装 这里选择命令安装curl -fsSL …

蓝桥杯---力扣题库第38题目解析

文章目录 1.题目重述2.外观数列举例说明3.思路分析&#xff08;双指针模拟&#xff09;4.代码说明 1.题目重述 外观数列实际上就是给你一串数字&#xff0c;我们需要对于这个数据进行一个简单的描述罢了&#xff1b; 2.外观数列举例说明 外观数列都是从1开始的&#xff0c;也…

oCam:免费且强大的录屏软件

今天给大家推荐一个非常好的录屏软件。几乎可以满足你日常工作的需求。而且软件完全免费&#xff0c;没有任何的广告。 oCam&#xff1a;免费且强大的录屏软件 oCam是一款功能强大的免费录屏软件&#xff0c;支持屏幕录制、游戏录制和音频录制等多种模式&#xff0c;能够满足不…

【GitLab CI/CD 实践】从 0 到 1 搭建高效自动化部署流程

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…