Shell文本处理

文本处理是Linux系统管理的重要技能,通过grep、sed、awk等工具,可以高效地搜索、过滤、转换和处理文本数据。本章将详细介绍这些强大的文本处理工具。


一、正则表达式

1.1 基础正则表达式

1.1.1 元字符

常用元字符

元字符 说明 示例
. 匹配任意单个字符 a.c 匹配 abc、adc、a1c
* 匹配前一个字符0次或多次 ab*c 匹配 ac、abc、abbc
^ 匹配行首 ^root 匹配以root开头的行
$ 匹配行尾 bash$ 匹配以bash结尾的行
[] 匹配字符集合 [abc] 匹配a或b或c
[^] 匹配不在集合中的字符 [^0-9] 匹配非数字字符
\ 转义字符 \. 匹配点号本身
\< 匹配单词开头 \<root 匹配以root开头的单词
\> 匹配单词结尾 bash\> 匹配以bash结尾的单词

示例

# 匹配以root开头的行
grep '^root' /etc/passwd

# 匹配以bash结尾的行
grep 'bash$' /etc/passwd

# 匹配空行
grep '^$' /etc/passwd

# 匹配包含数字的行
grep '[0-9]' /etc/passwd

# 匹配不包含数字的行
grep '[^0-9]' /etc/passwd

# 匹配邮箱格式
grep '[a-zA-Z0-9._%+-]*@[a-zA-Z0-9.-]*\.[a-zA-Z]*' file.txt

东巴文理解:正则表达式是文本处理的基石,掌握元字符是关键。

1.1.2 字符类

预定义字符类

字符类 说明 等价于
[:alnum:] 字母和数字 [a-zA-Z0-9]
[:alpha:] 字母 [a-zA-Z]
[:digit:] 数字 [0-9]
[:lower:] 小写字母 [a-z]
[:upper:] 大写字母 [A-Z]
[:space:] 空白字符 [ \t\n\r\f\v]
[:punct:] 标点符号 [!"#$%&'()*+,-./:;<=>?@[\]^_\{|}~]`

示例

# 匹配数字
grep '[[:digit:]]' /etc/passwd

# 匹配字母
grep '[[:alpha:]]' /etc/passwd

# 匹配小写字母
grep '[[:lower:]]' /etc/passwd

# 匹配空白字符
grep '[[:space:]]' /etc/passwd

1.2 扩展正则表达式

1.2.1 扩展元字符

扩展正则表达式元字符

元字符 说明 示例
+ 匹配前一个字符1次或多次 ab+c 匹配 abc、abbc、abbbc
? 匹配前一个字符0次或1次 ab?c 匹配 ac、abc
` ` 或运算符
() 分组 (ab)+ 匹配 ab、abab、ababab
{n} 匹配前一个字符n次 a{3} 匹配 aaa
{n,} 匹配前一个字符至少n次 a{3,} 匹配 aaa、aaaa、aaaaa
{n,m} 匹配前一个字符n到m次 a{2,4} 匹配 aa、aaa、aaaa

示例

# 使用扩展正则表达式(-E选项)
grep -E 'ab+c' file.txt      # 匹配 abc、abbc、abbbc
grep -E 'ab?c' file.txt      # 匹配 ac、abc
grep -E 'a|b' file.txt       # 匹配 a 或 b
grep -E '(ab)+' file.txt     # 匹配 ab、abab、ababab
grep -E 'a{3}' file.txt      # 匹配 aaa
grep -E 'a{3,}' file.txt     # 匹配 aaa、aaaa、aaaaa
grep -E 'a{2,4}' file.txt    # 匹配 aa、aaa、aaaa

# 匹配IP地址
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' file.txt

# 匹配邮箱
grep -E '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' file.txt

# 匹配手机号
grep -E '1[3-9][0-9]{9}' file.txt

东巴文提示:使用-E选项启用扩展正则表达式,或使用egrep命令。

1.2.2 实战案例

匹配IP地址

#!/bin/bash

# 匹配IP地址
ip_pattern='([0-9]{1,3}\.){3}[0-9]{1,3}'

# 从文件中提取IP
grep -Eo $ip_pattern access.log

# 从命令输出中提取IP
ip addr show | grep -Eo $ip_pattern

# 验证IP地址格式
function is_valid_ip() {
    local ip="$1"
    
    if [[ $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
        # 检查每个数字是否在0-255范围内
        IFS='.' read -ra octets <<< "$ip"
        for octet in "${octets[@]}"; do
            if (( octet < 0 || octet > 255 )); then
                return 1
            fi
        done
        return 0
    else
        return 1
    fi
}

# 测试
is_valid_ip "192.168.1.1" && echo "有效IP"
is_valid_ip "256.1.1.1" || echo "无效IP"

匹配邮箱地址

#!/bin/bash

# 匹配邮箱地址
email_pattern='[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'

# 从文件中提取邮箱
grep -Eo $email_pattern contacts.txt

# 验证邮箱格式
function is_valid_email() {
    local email="$1"
    
    if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
        return 0
    else
        return 1
    fi
}

# 测试
is_valid_email "user@example.com" && echo "有效邮箱"
is_valid_email "invalid-email" || echo "无效邮箱"

匹配URL

#!/bin/bash

# 匹配URL
url_pattern='https?://[a-zA-Z0-9.-]+(/[a-zA-Z0-9._~:/?#@!$&()*+,;=-]*)?'

# 从文件中提取URL
grep -Eo $url_pattern webpage.html

# 验证URL格式
function is_valid_url() {
    local url="$1"
    
    if [[ $url =~ ^https?://[a-zA-Z0-9.-]+ ]]; then
        return 0
    else
        return 1
    fi
}

# 测试
is_valid_url "https://www.example.com" && echo "有效URL"
is_valid_url "invalid-url" || echo "无效URL"

二、grep命令

2.1 基础用法

2.1.1 基本搜索

语法格式

grep [选项] '模式' 文件

常用选项

选项 说明
-i 忽略大小写
-v 反向匹配(显示不匹配的行)
-n 显示行号
-c 只显示匹配的行数
-l 只显示文件名
-w 匹配整个单词
-x 匹配整行
-o 只显示匹配的部分
-E 使用扩展正则表达式
-F 固定字符串匹配(不使用正则)
-r 递归搜索目录
-A n 显示匹配行及后n行
-B n 显示匹配行及前n行
-C n 显示匹配行及前后各n行

示例

# 基本搜索
grep "root" /etc/passwd

# 忽略大小写
grep -i "ROOT" /etc/passwd

# 显示行号
grep -n "root" /etc/passwd

# 反向匹配
grep -v "nologin" /etc/passwd

# 只显示匹配行数
grep -c "root" /etc/passwd

# 匹配整个单词
grep -w "root" /etc/passwd

# 匹配整行
grep -x "root:x:0:0:root:/root:/bin/bash" /etc/passwd

# 只显示匹配的部分
grep -o "[0-9]\+" /etc/passwd

# 显示匹配行及后3行
grep -A 3 "root" /etc/passwd

# 显示匹配行及前3行
grep -B 3 "root" /etc/passwd

# 显示匹配行及前后各3行
grep -C 3 "root" /etc/passwd

东巴文理解grep是最常用的文本搜索工具,掌握常用选项能提高效率。

2.1.2 递归搜索

搜索目录中的文件

# 递归搜索目录
grep -r "error" /var/log/

# 递归搜索,只显示文件名
grep -rl "error" /var/log/

# 递归搜索,显示行号
grep -rn "error" /var/log/

# 指定文件类型
grep -r --include="*.log" "error" /var/log/

# 排除文件类型
grep -r --exclude="*.gz" "error" /var/log/

# 排除目录
grep -r --exclude-dir="archive" "error" /var/log/

实战案例

#!/bin/bash

# 在代码中搜索函数定义
grep -rn "function\|def\|void" ./src/

# 在日志中搜索错误
grep -rn "ERROR\|FATAL\|CRITICAL" /var/log/

# 搜索配置文件中的设置
grep -rn "ServerName\|DocumentRoot" /etc/apache2/

# 搜索特定日期的日志
grep -rn "$(date +%Y-%m-%d)" /var/log/

2.2 高级用法

2.2.1 多模式匹配

使用多个模式

# 匹配多个模式(或关系)
grep -E "error|warning|critical" /var/log/syslog

# 从文件读取模式
cat > patterns.txt << EOF
error
warning
critical
EOF

grep -f patterns.txt /var/log/syslog

# 匹配所有模式(与关系)
grep "error" /var/log/syslog | grep "database"

# 排除多个模式
grep -v -E "debug|info|notice" /var/log/syslog

2.2.2 上下文显示

显示匹配行的上下文

# 显示匹配行及后5行
grep -A 5 "error" /var/log/syslog

# 显示匹配行及前5行
grep -B 5 "error" /var/log/syslog

# 显示匹配行及前后各5行
grep -C 5 "error" /var/log/syslog

# 显示多个匹配的上下文
grep -C 2 -E "error|warning" /var/log/syslog

2.2.3 统计与排序

统计匹配结果

# 统计每个文件中的匹配行数
grep -c "error" /var/log/*.log

# 统计匹配的总行数
grep "error" /var/log/*.log | wc -l

# 统计匹配的文件数
grep -l "error" /var/log/*.log | wc -l

# 统计每个IP出现的次数
grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' access.log | sort | uniq -c | sort -rn

# 统计每个URL的访问次数
grep -oE '/[a-zA-Z0-9./?=_-]*' access.log | sort | uniq -c | sort -rn | head -10

东巴文实战:结合sortuniq等命令,可以进行强大的数据分析。

2.3 实战案例

2.3.1 日志分析

#!/bin/bash
#===============================================================================
# 脚本名称:log_analyzer.sh
# 脚本功能:日志分析脚本
# 作者:东巴文
#===============================================================================

LOG_FILE="/var/log/nginx/access.log"

echo "=== 日志分析报告 ==="
echo "生成时间:$(date)"
echo

# 1. 总请求数
total_requests=$(wc -l < "$LOG_FILE")
echo "总请求数:$total_requests"

# 2. 独立IP数
unique_ips=$(grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' "$LOG_FILE" | sort -u | wc -l)
echo "独立IP数:$unique_ips"

# 3. 最常访问的IP(前10)
echo -e "\n最常访问的IP(前10):"
grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -10

# 4. 最常访问的URL(前10)
echo -e "\n最常访问的URL(前10):"
awk '{print $7}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -10

# 5. HTTP状态码统计
echo -e "\nHTTP状态码统计:"
awk '{print $9}' "$LOG_FILE" | sort | uniq -c | sort -rn

# 6. 404错误统计
echo -e "\n404错误统计:"
grep ' 404 ' "$LOG_FILE" | wc -l

# 7. 500错误统计
echo -e "\n500错误统计:"
grep ' 500 ' "$LOG_FILE" | wc -l

# 8. 按小时统计访问量
echo -e "\n按小时统计访问量:"
awk '{print substr($4, 14, 2)}' "$LOG_FILE" | sort | uniq -c

# 9. 按日期统计访问量
echo -e "\n按日期统计访问量:"
awk '{print substr($4, 2, 11)}' "$LOG_FILE" | sort | uniq -c

# 10. 搜索引擎爬虫统计
echo -e "\n搜索引擎爬虫统计:"
grep -iE 'googlebot|baiduspider|bingbot|yandexbot' "$LOG_FILE" | wc -l

2.3.2 代码搜索

#!/bin/bash
#===============================================================================
# 脚本名称:code_search.sh
# 脚本功能:代码搜索脚本
# 作者:东巴文
#===============================================================================

# 搜索函数定义
function search_function() {
    local keyword="$1"
    local directory="${2:-.}"
    
    echo "搜索函数定义:$keyword"
    grep -rn --include="*.py" --include="*.sh" --include="*.js" \
        -E "(function|def|void)\s+$keyword" "$directory"
}

# 搜索变量定义
function search_variable() {
    local keyword="$1"
    local directory="${2:-.}"
    
    echo "搜索变量定义:$keyword"
    grep -rn --include="*.py" --include="*.sh" --include="*.js" \
        -E "(var|let|const|=)\s*$keyword" "$directory"
}

# 搜索TODO注释
function search_todo() {
    local directory="${1:-.}"
    
    echo "搜索TODO注释:"
    grep -rn --include="*.py" --include="*.sh" --include="*.js" \
        -iE "TODO|FIXME|XXX|HACK" "$directory"
}

# 搜索错误处理
function search_error() {
    local directory="${1:-.}"
    
    echo "搜索错误处理:"
    grep -rn --include="*.py" --include="*.sh" --include="*.js" \
        -iE "error|exception|catch|try" "$directory"
}

# 主菜单
function main() {
    local keyword="$1"
    local directory="${2:-.}"
    
    echo "=== 代码搜索工具 ==="
    echo "关键词:$keyword"
    echo "目录:$directory"
    echo
    
    search_function "$keyword" "$directory"
    echo
    search_variable "$keyword" "$directory"
}

# 执行
main "$@"

三、sed编辑器

3.1 基础用法

3.1.1 基本语法

语法格式

sed [选项] '命令' 文件

常用选项

选项 说明
-n 抑制自动输出
-e 多点编辑
-f 从文件读取脚本
-i 直接修改文件
-r 使用扩展正则表达式

常用命令

命令 说明
p 打印
d 删除
s 替换
a 在指定行后追加
i 在指定行前插入
c 替换整行
y 字符转换

示例

# 打印第3行
sed -n '3p' /etc/passwd

# 打印第3到5行
sed -n '3,5p' /etc/passwd

# 打印最后一行
sed -n '$p' /etc/passwd

# 打印包含root的行
sed -n '/root/p' /etc/passwd

# 删除第3行
sed '3d' /etc/passwd

# 删除第3到5行
sed '3,5d' /etc/passwd

# 删除空行
sed '/^$/d' /etc/passwd

# 删除包含root的行
sed '/root/d' /etc/passwd

东巴文理解sed是流编辑器,按行处理文本,不会修改原文件(除非使用-i选项)。

3.1.2 替换操作

基本替换

# 替换每行的第一个匹配
sed 's/old/new/' file.txt

# 替换每行的所有匹配
sed 's/old/new/g' file.txt

# 替换第2个匹配
sed 's/old/new/2' file.txt

# 替换第3到第5行的第一个匹配
sed '3,5s/old/new/' file.txt

# 只打印替换的行
sed -n 's/old/new/p' file.txt

# 忽略大小写
sed 's/old/new/gi' file.txt

# 直接修改文件
sed -i 's/old/new/g' file.txt

# 备份原文件后修改
sed -i.bak 's/old/new/g' file.txt

替换标志

标志 说明
g 全局替换
i 忽略大小写
n 替换第n个匹配
p 打印替换的行
w file 将替换结果写入文件

示例

# 全局替换
sed 's/root/admin/g' /etc/passwd

# 忽略大小写替换
sed 's/ROOT/admin/gi' /etc/passwd

# 替换第2个匹配
sed 's/:/;/2' /etc/passwd

# 只打印替换的行
sed -n 's/root/admin/gp' /etc/passwd

# 将替换结果写入文件
sed -n 's/root/admin/gpw output.txt' /etc/passwd

3.2 高级用法

3.2.1 地址定界

行号定界

# 处理第3行
sed '3s/old/new/' file.txt

# 处理第3到5行
sed '3,5s/old/new/' file.txt

# 处理最后一行
sed '$s/old/new/' file.txt

# 处理第3行到最后一行
sed '3,$s/old/new/' file.txt

# 处理奇数行
sed '1~2s/old/new/' file.txt

# 处理偶数行
sed '2~2s/old/new/' file.txt

模式定界

# 处理包含pattern的行
sed '/pattern/s/old/new/' file.txt

# 处理从pattern1到pattern2的行
sed '/pattern1/,/pattern2/s/old/new/' file.txt

# 处理从第3行到包含pattern的行
sed '3,/pattern/s/old/new/' file.txt

# 处理不包含pattern的行
sed '/pattern/!s/old/new/' file.txt

3.2.2 多点编辑

使用-e选项

# 多个替换操作
sed -e 's/old1/new1/g' -e 's/old2/new2/g' file.txt

# 删除和替换
sed -e '/^$/d' -e 's/old/new/g' file.txt

# 使用分号分隔
sed 's/old1/new1/g; s/old2/new2/g' file.txt

3.2.3 保持空间

高级命令

命令 说明
h 复制模式空间到保持空间
H 追加模式空间到保持空间
g 复制保持空间到模式空间
G 追加保持空间到模式空间
x 交换模式空间和保持空间
n 读取下一行到模式空间
N 追加下一行到模式空间

示例

# 反转文件行序
sed '1!G;h;$!d' file.txt

# 合并两行
sed 'N;s/\n/ /' file.txt

# 显示奇数行
sed 'n;d' file.txt

# 显示偶数行
sed '1d;n;d' file.txt

# 删除重复行
sed '$!N; /^\(.*\)\n\1$/!P; D' file.txt

东巴文提示:保持空间是sed的高级特性,可以实现复杂的文本处理。

3.3 实战案例

3.3.1 配置文件修改

#!/bin/bash
#===============================================================================
# 脚本名称:config_editor.sh
# 脚本功能:配置文件修改脚本
# 作者:东巴文
#===============================================================================

CONFIG_FILE="/etc/nginx/nginx.conf"

# 备份配置文件
cp "$CONFIG_FILE" "${CONFIG_FILE}.bak"

# 修改监听端口
sed -i 's/listen 80;/listen 8080;/' "$CONFIG_FILE"

# 修改worker进程数
sed -i 's/worker_processes auto;/worker_processes 4;/' "$CONFIG_FILE"

# 启用gzip压缩
sed -i 's/# gzip on;/gzip on;/' "$CONFIG_FILE"

# 添加server配置
sed -i '/server {/a\    listen 443 ssl;' "$CONFIG_FILE"

# 删除注释行
sed -i '/^[[:space:]]*#/d' "$CONFIG_FILE"

# 删除空行
sed -i '/^$/d' "$CONFIG_FILE"

echo "配置文件修改完成"

3.3.2 日志处理

#!/bin/bash
#===============================================================================
# 脚本名称:log_processor.sh
# 脚本功能:日志处理脚本
# 作者:东巴文
#===============================================================================

LOG_FILE="/var/log/nginx/access.log"

# 1. 提取IP地址
echo "提取IP地址:"
sed -n 's/^\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/p' "$LOG_FILE" | head -10

# 2. 提取URL
echo -e "\n提取URL:"
sed -n 's/.*"\([A-Z]\+\) \([^ ]*\) .*/\1 \2/p' "$LOG_FILE" | head -10

# 3. 提取HTTP状态码
echo -e "\n提取HTTP状态码:"
sed -n 's/.*" \([0-9]\{3\}\) .*/\1/p' "$LOG_FILE" | sort | uniq -c | sort -rn | head -10

# 4. 提取User-Agent
echo -e "\n提取User-Agent:"
sed -n 's/.*"\([^"]*\)"$/\1/p' "$LOG_FILE" | head -10

# 5. 替换敏感信息
echo -e "\n替换敏感信息:"
sed 's/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/xxx.xxx.xxx.xxx/g' "$LOG_FILE" | head -5

# 6. 格式化日志
echo -e "\n格式化日志:"
sed 's/\[/%[/; s/\]/%]/' "$LOG_FILE" | head -5

3.3.3 文本转换

#!/bin/bash
#===============================================================================
# 脚本名称:text_converter.sh
# 脚本功能:文本转换脚本
# 作者:东巴文
#===============================================================================

# 1. Windows换行符转Unix换行符
sed -i 's/\r$//' file.txt

# 2. Unix换行符转Windows换行符
sed -i 's/$/\r/' file.txt

# 3. 删除行首空格
sed 's/^[[:space:]]*//' file.txt

# 4. 删除行尾空格
sed 's/[[:space:]]*$//' file.txt

# 5. 删除行首和行尾空格
sed 's/^[[:space:]]*//;s/[[:space:]]*$//' file.txt

# 6. 删除HTML标签
sed 's/<[^>]*>//g' file.html

# 7. 提取HTML标签内容
sed -n 's/.*<title>\(.*\)<\/title>.*/\1/p' file.html

# 8. 大写转小写
sed 's/[A-Z]/\l&/g' file.txt

# 9. 小写转大写
sed 's/[a-z]/\u&/g' file.txt

# 10. 首字母大写
sed 's/\b\(.\)/\u\1/' file.txt

四、awk编程

4.1 基础用法

4.1.1 基本语法

语法格式

awk [选项] '模式 { 动作 }' 文件

常用选项

选项 说明
-F 指定字段分隔符
-v 定义变量
-f 从文件读取脚本

内置变量

变量 说明
$0 整行内容
$1~$n 第n个字段
NF 字段数
NR 行号
FNR 文件行号
FS 字段分隔符
RS 记录分隔符
OFS 输出字段分隔符
ORS 输出记录分隔符
FILENAME 文件名

示例

# 打印整行
awk '{print $0}' /etc/passwd

# 打印第1个字段
awk -F: '{print $1}' /etc/passwd

# 打印第1和第7个字段
awk -F: '{print $1, $7}' /etc/passwd

# 打印行号和整行
awk '{print NR, $0}' /etc/passwd

# 打印字段数和整行
awk -F: '{print NF, $0}' /etc/passwd

# 打印最后一个字段
awk -F: '{print $NF}' /etc/passwd

# 打印倒数第2个字段
awk -F: '{print $(NF-1)}' /etc/passwd

东巴文理解awk是强大的文本处理工具,按字段处理文本,支持编程。

4.1.2 模式匹配

使用模式

# 匹配包含root的行
awk '/root/ {print $0}' /etc/passwd

# 匹配以root开头的行
awk '/^root/ {print $0}' /etc/passwd

# 匹配以bash结尾的行
awk /bash$/ {print $0}' /etc/passwd

# 匹配第3个字段为0的行
awk -F: '$3 == 0 {print $0}' /etc/passwd

# 匹配第3个字段大于等于1000的行
awk -F: '$3 >= 1000 {print $0}' /etc/passwd

# 匹配第1个字段为root或nginx的行
awk -F: '$1 == "root" || $1 == "nginx" {print $0}' /etc/passwd

# 匹配第7个字段包含bash的行
awk -F: '$7 ~ /bash/ {print $0}' /etc/passwd

# 匹配第7个字段不包含nologin的行
awk -F: '$7 !~ /nologin/ {print $0}' /etc/passwd

行号模式

# 打印第3行
awk 'NR == 3 {print $0}' /etc/passwd

# 打印第3到5行
awk 'NR >= 3 && NR <= 5 {print $0}' /etc/passwd

# 打印奇数行
awk 'NR % 2 == 1 {print $0}' /etc/passwd

# 打印偶数行
awk 'NR % 2 == 0 {print $0}' /etc/passwd

# 打印前10行
awk 'NR <= 10 {print $0}' /etc/passwd

# 打印最后一行
awk 'END {print $0}' /etc/passwd

4.2 高级用法

4.2.1 条件判断

if-else语句

# 条件判断
awk -F: '{
    if ($3 == 0) {
        print $1 " is root"
    } else if ($3 >= 1000) {
        print $1 " is normal user"
    } else {
        print $1 " is system user"
    }
}' /etc/passwd

# 简写
awk -F: '$3 == 0 {print $1 " is root"} $3 >= 1000 {print $1 " is normal user"}' /etc/passwd

条件运算符

# 三目运算符
awk -F: '{print $1, ($3 == 0) ? "root" : "user"}' /etc/passwd

# 逻辑运算符
awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd
awk -F: '$3 == 0 || $3 == 65534 {print $1}' /etc/passwd

4.2.2 循环

for循环

# 遍历字段
awk -F: '{
    for (i = 1; i <= NF; i++) {
        print "Field " i ": " $i
    }
}' /etc/passwd

# 计算总和
awk '{
    sum = 0
    for (i = 1; i <= NF; i++) {
        sum += $i
    }
    print "Sum:", sum
}' numbers.txt

while循环

# while循环
awk -F: '{
    i = 1
    while (i <= NF) {
        print "Field " i ": " $i
        i++
    }
}' /etc/passwd

# do-while循环
awk -F: '{
    i = 1
    do {
        print "Field " i ": " $i
        i++
    } while (i <= NF)
}' /etc/passwd

4.2.3 数组

数组操作

# 统计每个shell的用户数
awk -F: '{
    shell[$7]++
}
END {
    for (s in shell) {
        print s ": " shell[s]
    }
}' /etc/passwd

# 统计每个IP的访问次数
awk '{
    ip[$1]++
}
END {
    for (i in ip) {
        print i ": " ip[i]
    }
}' access.log

# 统计每个URL的访问次数
awk '{
    url[$7]++
}
END {
    for (u in url) {
        print u ": " url[u]
    }
}' access.log

东巴文提示awk的数组是关联数组,可以使用字符串作为索引。

4.3 内置函数

4.3.1 字符串函数

常用字符串函数

函数 说明 示例
length(s) 字符串长度 length("hello") → 5
substr(s, i, n) 子字符串 substr("hello", 2, 3) → "ell"
index(s, t) 子串位置 index("hello", "ll") → 3
split(s, a, fs) 分割字符串 split("a:b:c", arr, ":")
sub(r, s, t) 替换第一个匹配 sub(/old/, "new", $0)
gsub(r, s, t) 替换所有匹配 gsub(/old/, "new", $0)
tolower(s) 转小写 tolower("HELLO") → "hello"
toupper(s) 转大写 toupper("hello") → "HELLO"
sprintf(fmt, ...) 格式化字符串 sprintf("%d", 10) → "10"

示例

# 字符串长度
awk '{print length($0)}' /etc/passwd

# 提取子字符串
awk -F: '{print substr($1, 1, 3)}' /etc/passwd

# 查找子串位置
awk -F: '{print index($0, "root")}' /etc/passwd

# 分割字符串
awk -F: '{
    n = split($7, arr, "/")
    for (i = 1; i <= n; i++) {
        print arr[i]
    }
}' /etc/passwd

# 替换字符串
awk -F: '{sub(/root/, "admin"); print $0}' /etc/passwd
awk -F: '{gsub(/root/, "admin"); print $0}' /etc/passwd

# 大小写转换
awk -F: '{print toupper($1)}' /etc/passwd
awk -F: '{print tolower($1)}' /etc/passwd

4.3.2 数值函数

常用数值函数

函数 说明 示例
int(x) 取整 int(3.7) → 3
sqrt(x) 平方根 sqrt(16) → 4
exp(x) e的x次方 exp(1) → 2.71828
log(x) 自然对数 log(10) → 2.30259
sin(x) 正弦 sin(0) → 0
cos(x) 余弦 cos(0) → 1
rand() 随机数 rand() → 0-1之间的随机数
srand(x) 设置随机种子 srand()

示例

# 取整
awk '{print int($1)}' numbers.txt

# 平方根
awk '{print sqrt($1)}' numbers.txt

# 随机数
awk 'BEGIN {srand(); for (i=1; i<=10; i++) print int(rand()*100)}'

4.3.3 时间函数

时间函数

函数 说明
systime() 当前时间戳
mktime(datespec) 时间戳转换
strftime(format, timestamp) 格式化时间

示例

# 当前时间戳
awk 'BEGIN {print systime()}'

# 格式化时间
awk 'BEGIN {print strftime("%Y-%m-%d %H:%M:%S", systime())}'

# 时间计算
awk 'BEGIN {
    now = systime()
    tomorrow = now + 86400
    print "今天:", strftime("%Y-%m-%d", now)
    print "明天:", strftime("%Y-%m-%d", tomorrow)
}'

4.4 实战案例

4.4.1 日志分析

#!/bin/bash
#===============================================================================
# 脚本名称:log_analyzer_awk.sh
# 脚本功能:使用awk分析日志
# 作者:东巴文
#===============================================================================

LOG_FILE="/var/log/nginx/access.log"

echo "=== Nginx访问日志分析 ==="

# 1. 总请求数
echo -e "\n总请求数:"
awk 'END {print NR}' "$LOG_FILE"

# 2. 独立IP数
echo -e "\n独立IP数:"
awk '{ip[$1]++} END {for (i in ip) count++} END {print count}' "$LOG_FILE"

# 3. 最常访问的IP(前10)
echo -e "\n最常访问的IP(前10):"
awk '{ip[$1]++} END {for (i in ip) print ip[i], i}' "$LOG_FILE" | sort -rn | head -10

# 4. 最常访问的URL(前10)
echo -e "\n最常访问的URL(前10):"
awk '{url[$7]++} END {for (u in url) print url[u], u}' "$LOG_FILE" | sort -rn | head -10

# 5. HTTP状态码统计
echo -e "\nHTTP状态码统计:"
awk '{status[$9]++} END {for (s in status) print status[s], s}' "$LOG_FILE" | sort -rn

# 6. 平均响应时间
echo -e "\n平均响应时间:"
awk '{sum+=$NF; count++} END {print sum/count " ms"}' "$LOG_FILE"

# 7. 按小时统计访问量
echo -e "\n按小时统计访问量:"
awk '{hour[substr($4, 14, 2)]++} END {for (h in hour) print h, hour[h]}' "$LOG_FILE" | sort

# 8. 按日期统计访问量
echo -e "\n按日期统计访问量:"
awk '{date[substr($4, 2, 11)]++} END {for (d in date) print d, date[d]}' "$LOG_FILE" | sort

# 9. 统计每个IP的流量
echo -e "\n统计每个IP的流量(前10):"
awk '{traffic[$1]+=$10} END {for (i in traffic) print traffic[i], i}' "$LOG_FILE" | sort -rn | head -10

# 10. 统计User-Agent
echo -e "\n统计User-Agent(前10):"
awk '{gsub(/"/, "", $12); ua[$12]++} END {for (u in ua) print ua[u], u}' "$LOG_FILE" | sort -rn | head -10

4.4.2 数据处理

#!/bin/bash
#===============================================================================
# 脚本名称:data_processor.sh
# 脚本功能:数据处理脚本
# 作者:东巴文
#===============================================================================

# 1. 计算平均值
echo "计算平均值:"
awk '{sum+=$1; count++} END {print "Average:", sum/count}' numbers.txt

# 2. 计算最大值
echo -e "\n计算最大值:"
awk 'BEGIN {max=0} {if ($1>max) max=$1} END {print "Max:", max}' numbers.txt

# 3. 计算最小值
echo -e "\n计算最小值:"
awk 'BEGIN {min=999999} {if ($1<min) min=$1} END {print "Min:", min}' numbers.txt

# 4. 计算总和
echo -e "\n计算总和:"
awk '{sum+=$1} END {print "Sum:", sum}' numbers.txt

# 5. 统计行数
echo -e "\n统计行数:"
awk 'END {print "Total lines:", NR}' numbers.txt

# 6. 统计字段数
echo -e "\n统计字段数:"
awk '{print "Line", NR, "has", NF, "fields"}' data.txt

# 7. 过滤数据
echo -e "\n过滤大于100的数据:"
awk '$1 > 100 {print $0}' numbers.txt

# 8. 数据排序
echo -e "\n数据排序:"
awk '{print $0}' numbers.txt | sort -n

# 9. 去重
echo -e "\n去重:"
awk '!seen[$0]++' data.txt

# 10. 数据格式化
echo -e "\n数据格式化:"
awk '{printf "%-10s %10d %10.2f\n", $1, $2, $3}' data.txt

4.4.3 系统监控

#!/bin/bash
#===============================================================================
# 脚本名称:system_monitor.sh
# 脚本功能:系统监控脚本
# 作者:东巴文
#===============================================================================

echo "=== 系统监控报告 ==="
echo "生成时间:$(date)"
echo

# 1. CPU使用率
echo "CPU使用率:"
top -bn1 | awk '/Cpu(s)/ {
    printf "用户: %.1f%%\n", $2
    printf "系统: %.1f%%\n", $4
    printf "空闲: %.1f%%\n", $8
}'

# 2. 内存使用
echo -e "\n内存使用:"
free | awk '/Mem:/ {
    total=$2/1024
    used=$3/1024
    free=$4/1024
    printf "总计: %.1f MB\n", total
    printf "已用: %.1f MB\n", used
    printf "空闲: %.1f MB\n", free
    printf "使用率: %.1f%%\n", (used/total)*100
}'

# 3. 磁盘使用
echo -e "\n磁盘使用:"
df -h | awk '/^\/dev/ {
    printf "%-20s %10s %10s %10s %10s\n", $1, $2, $3, $4, $5
}'

# 4. 网络连接
echo -e "\n网络连接统计:"
netstat -an | awk '/^tcp/ {
    state[$6]++
}
END {
    for (s in state) {
        print s ": " state[s]
    }
}'

# 5. 进程统计
echo -e "\n进程统计:"
ps aux | awk 'NR>1 {
    user[$1]++
}
END {
    for (u in user) {
        print u ": " user[u]
    }
}'

# 6. 用户登录
echo -e "\n用户登录:"
who | awk '{print $1, $2, $3, $4}'

# 7. 系统负载
echo -e "\n系统负载:"
awk '{print "1分钟:", $1, "5分钟:", $2, "15分钟:", $3}' /proc/loadavg

# 8. 网络流量
echo -e "\n网络流量:"
awk '/eth0:/ {
    printf "接收: %.2f MB\n", $2/1024/1024
    printf "发送: %.2f MB\n", $10/1024/1024
}' /proc/net/dev

五、本章小结

5.1 核心要点

✅ 掌握正则表达式语法 ✅ 熟练使用grep搜索文本 ✅ 学会sed编辑文本 ✅ 掌握awk处理文本

5.2 验证清单

完成本章学习后,请确认您能够:

  • 使用正则表达式匹配文本
  • 使用grep搜索和过滤文本
  • 使用sed替换和编辑文本
  • 使用awk处理和分析文本

东巴文(db-w.cn) - 让Linux学习更简单