跳至主要內容

文本处理

Mr.Liu大约 8 分钟Linuxsedawkgrep

文本处理

awk

awk​是一种用于文本处理和数据抽取的强大命令行工具。它基于模式匹配和动作执行的原则,允许您在文本文件中查找特定模式并执行相应的操作。

awk​的基本语法为:

awk 'pattern { action }' input_file

以下是一些常见的 awk​ 选项及案例说明

列抽取

从文本文件中抽取指定的列。

awk '{print $2}' data.txt

这个命令从名为 data.txt​ 的文本文件中,每行提取第二列的数据并输出。

  • $2​ 表示第二列。列的计数是从 1 开始的。

  • $0​ 表示整行内容。

特殊变量

awk 'END {print NR}' file.txt

这个命令在名为 file.txt​ 的文件结束时输出文件的总行数。

  1. ​​NR​ 表示当前行号
  2. NF​ 表示当前行中字段(或列)的数量
  3. ​**FS(字段分隔符)**:表示字段之间的分隔符。默认情况下,FS​ 的值是空格或制表符(\t​)。你可以使用 -F​ 命令行选项来改变字段分隔符。
  4. ​**RS(记录分隔符)**:表示记录(行)之间的分隔符。默认情况下,RS​ 的值是换行符(\n​)。你可以使用 -F​ 命令行选项来改变记录分隔符。
  5. ​**OFS(输出字段分隔符)**:表示输出时字段之间的分隔符。默认情况下,OFS​ 的值与 FS​ 相同。
  6. ​**ORS(输出记录分隔符)**:表示输出时记录之间的分隔符。默认情况下,ORS​ 的值是换行符(\n​)。
  7. ​**FILENAME**​:表示当前正在处理的文件的名称。

自定义分隔符

awk -F ':' '{print $1, $7}' /etc/passwd

使用冒号作为字段分隔符,提取 /etc/passwd​ 文件的第一列(用户名)和第七列(用户的登录Shell)。

默认使用空格作为字段分隔符,-F​ 选项用于指定字段分隔符。

自定义输出分隔符

awk 'BEGIN {OFS="\t"} {print $1, $2}' data.txt

设置输出分隔符为制表符,然后每行输出第一、第二和第三列的数据,用制表符分隔。

默认使用空格作为输出分隔符。可以使用内置的 OFS​ 变量来自定义输出分隔符。

自定义变量参数

awk -v OFS=":" '{print $1, $2, $3}' data.txt

设置输出分隔符,输出的每列字段之间用:​分割

awk -v math_weight=0.6 -v eng_weight=0.4 '{ total = ($2 * math_weight) + ($3 * eng_weight); print $1, "Total:", total }' grades.txt

设置数学成绩的权重为0.6,英语成绩的权重为0.4,然后计算每个学生的总成绩

格式化输出

awk '{printf "Name: %-10s Age: %2d\n", $1, $3}' data.txt

将名为 data.txt​ 的文件中的第一列(姓名)和第三列(年龄)格式化输出,确保名字占据10个字符的宽度,年龄占据2个字符的宽度。

  • %​:表示格式化字符串的起始标记。
  • -​:表示左对齐文本。如果没有 -​,则默认是右对齐。
  • 10​:表示字段的宽度。在这里,它指定字符串字段占据的总宽度为 10 个字符。
  • s/d​:表示字符串的数据类型。

初始块/结束块

只在第一次和最后一次执行

awk 'BEGIN {
    print "Student Scores:"
    print "----------------"
}
{
    print "Student:", $1, "Scores:", $2
}
END {
    print "----------------"
    print "End of Student Scores"
}' student_scores.txt

使用 BEGIN​ 块在处理开始时输出提示信息,然后在每行数据处理时只输出每个学生的名字和成绩字段。最后,我们使用 END​ 块在处理结束时输出结束信息。

BEGIN​ 块来在处理开始时执行一些操作;END​ 块来在处理结束时执行一些操作。

条件结构

awk '{
    if ($2 > 50000) {
        category = "High"
    } else if ($2 > 30000) {
        category = "Medium"
    } else {
        category = "Low"
    }
    print $1, ":", category
}' employees.txt

使用 if​、else if​ 和 else​ 条件语句根据薪水水平将员工分为不同的分类,并打印出结果。

循环结构

for​ 循环

awk 'BEGIN { sum = 0 } { sum += $1 } END { print "Sum:", sum }' numbers.txt

BEGIN​ 部分用于初始化变量 sum​,然后每行的数字会被加到 sum​ 中,最后 END​ 部分打印出总和。

awk '{ 
    total = 0 
    for (i = 2; i <= NF; i++) { 
        total += $i 
    } 
    print $1, "Total:", total 
}' student_scores.txt

遍历从第二个字段开始的每个字段,并将它们相加以计算学生的总分。然后,我们使用 print​ 命令输出每个学生的姓名和总分。

while循环

awk '{
    total += $2
    count++
}
END {
    avg = total / count
    print "Average:", avg
    print "Students above average:"
    while (getline < "scores.txt" > 0) {
        if ($2 > avg) {
            print $1, $2
        }
    }
}' scores.txt

在while循环中,使用 getline 函数从文件中逐行读取数据,然后通过条件语句判断分数是否高于平均分,并输出相应的学生信息。

行处理

awk '/^host1/' logfile.txt

输出所有以 "host1" 开头的日志记录

# -i 忽略大小写
awk '/error/i' logfile.txt
# 设置参数,忽略大小写
awk 'BEGIN {IGNORECASE=1} /error/' logfile.txt
# 将内容转换为小写,然后使用 ~(匹配运算符)进行正则匹配
 awk 'tolower($0) ~ /error/ ' logfile.txt

匹配日志中所有包含error的行,忽略大小写

可以在模式部分使用斜杠 /​ 包裹正则表达式。

关联数组

awk '!seen[$0]++' input.txt

去重,只输出第一次出现的行

  1. 关联数组在 awk​ 中可以用于统计每行出现的次数,是因为它们提供了一种将键(索引)与值关联起来的方式。在这种情况下,数组的键是文本行的内容,而值是该行出现的次数。
awk '{ seen[$0]++ } END { for (record in seen) print record, "Count:", seen[record] }' input.txt

统计每行出现的次数

个性化定制搜索模式

假设您有一个名为 data.txt​ 的文本文件,其中包含以下内容:

this is wang ,not wan
that is chen, not che 
this is chen ,and wang ,not wan che 

提取is后面的第一个单词,和not 后面的第一个单词

awk '{match($0,/.+is([^,]+).+not(.+)/,a);print a[1],a[2]}' test

a[1]代表第一个()的内容,a[2]代表第二个()的内容,以此类推

grep

grep​ 是一个在 Unix-like 系统上常用的命令行工具,用于在文本文件中搜索指定的字符串模式,并返回匹配的行。它的名字来自于 "Global Regular Expression Print",表示它的原始目的是全局地搜索正则表达式并打印匹配的结果。

grep​ 的基本语法为:

grep [options] pattern [file ...]

以下是一些常见的 grep​ 选项及案例说明:

基本用法

在单个文件中搜索指定字符串模式,并返回匹配的行。

grep "pattern" filename

在多个文件中搜索

在多个文件中搜索指定字符串模式。

grep "pattern" file1 file2

递归搜索

在指定目录及其子目录中递归搜索。

grep -r "pattern" directory

忽略大小写

不区分大小写地搜索。

grep -i "pattern" filename

显示行号

显示匹配行的行号。

grep -n "pattern" filename

显示匹配的上下文

显示匹配行及其上下文的内容。

grep -C 2 "pattern" filename

只显示匹配的计数

显示匹配的行数而不显示具体内容。

grep -c "pattern" filename

反向搜索

显示不包含指定字符串模式的行。

grep -v "pattern" filename

使用正则表达式

使用正则表达式进行更复杂的模式匹配。

grep -E "regex pattern" filename

sed

sed​(Stream Editor)是一个流式文本编辑器,用于在输入流中进行文本替换、转换和编辑。它主要用于在命令行中进行文本处理,支持各种文本操作,如替换、插入、删除、打印等。sed​ 使用基于正则表达式的模式匹配来定位和操作文本。

以下是一些常用的 sed​ 案例介绍:

替换文本内容

sed 's/old_text/new_text/' input.txt

这会在输入文件中将第一个匹配的 "old_text" 替换为 "new_text"

上述命令仅在标准输出中显示结果,不会更改原始文件。

保存修改到新文件

sed 's/pattern/replacement/' input.txt > output.txt

将修改后的内容输出到一个新文件中

编辑原文件

sed -i 's/pattern/replacement/' input.txt

使用 -i​ 参数可以直接在原始文件上进行编辑,而不需要创建新文件

替换所有匹配

sed 's/old_text/new_text/g' input.txt

加上 g​ 标志将替换所有匹配的 "old_text"。

只打印匹配的行

sed -n '/pattern/p' input.txt

-n​ 参数表示只输出匹配的行,/pattern/p​ 表示匹配包含 "pattern" 的行并打印出来。

删除匹配的行

sed '/pattern/d' input.txt

删除包含 "pattern" 的行。

插入新行

# 在第二行之前插入一行文本
sed '2i\New line to insert' input.txt
# 在第二行之后插入一行文本
sed '2a\New line to after' input.txt

在固定的行前后插入数据

# 在包含hello的上一行插入up
sed -i '/hello/i\up' input.txt
# 在包含hello的下一行插入down
sed -i '/hello/a\down' input.txt

在匹配的行前后插入数据,有多个匹配行,那么在每一行上面或者下面都插入内容

# 在最后一行之后追加一行文本
sed '$a\New line to append' input.txt
# 最后一行之前追加一行文本
sed '$i\New line to append' input.txt

在文件最后一行的前后插入数据, $​ 表示最后一行。

使用正则表达式匹配

sed 's/[0-9]\+$/REPLACEMENT/' input.txt

在每一行的结尾匹配一个或多个数字并替换为 "REPLACEMENT"