简介
Linux 上有三个命令行工具用来处理数据,分别是grep
、sed
和 awk
,通常它们被称为 Shell 三剑客(或文本处理三剑客)。 它们是 Unix/Linux 系统中非常强大且常用的文本处理工具,各自擅长不同的任务:
-
grep
: 主要用于查找文本,根据模式(pattern)匹配行,并输出匹配的行。 -
sed
: 主要用于编辑文本,可以进行替换、删除、插入、追加等操作。它是一个流编辑器,逐行处理文本。 -
awk
: 主要用于分析和处理文本,可以将文本分割成字段,并对字段进行各种操作,例如计算、格式化输出等。它是一种编程语言,可以编写复杂的脚本。
这三个工具经常一起使用,构成强大的文本处理流水线。 例如,可以使用 grep
查找包含特定模式的行,然后使用 sed
对这些行进行编辑,最后使用 awk
对编辑后的结果进行分析和格式化输出。
grep
这是一个命令行搜索工具,可以在文件或输入流中搜索特定模式的行
结合管道命令将执行的结果传递给后面,对于完成一些复杂的操作很友好
好的,以下是 grep
的基本语法和常用选项:
基本结构
|
|
grep
: 调用 grep 命令。[OPTIONS]
: 可选的选项,用于修改 grep 的行为。PATTERN
: 要搜索的模式,通常是一个字符串或正则表达式。[FILE...]
: 要搜索的文件名。可以指定多个文件,如果省略,则 grep 从标准输入读取数据。
常用选项
-i
(或--ignore-case
): 忽略大小写。-v
(或--invert-match
): 反向匹配,只显示不匹配PATTERN
的行。-n
(或--line-number
): 显示匹配行的行号。-c
(或--count
): 只显示匹配行的数量,而不是匹配的行本身。-l
(或--files-with-matches
): 只显示包含匹配行的文件名,而不显示匹配的行本身。-L
(或--files-without-match
): 只显示不包含匹配行的文件名。-r
(或-R
或--recursive
): 递归搜索目录下的所有文件。-h
(或--no-filename
): 在输出中不显示文件名。 当搜索多个文件时,默认会显示文件名。-H
(或--with-filename
): 在输出中显示文件名。 这是默认行为,但可以用来覆盖-h
选项。-w
(或--word-regexp
): 只匹配完整的单词。-x
(或--line-regexp
): 只匹配整行都匹配的情况。-o
(或--only-matching
): 只显示匹配的部分,而不是整行。-q
(或--quiet
或--silent
): 静默模式,不输出任何信息,只返回退出状态码(0 表示找到匹配,1 表示没有找到匹配)。-s
(或--no-messages
): 禁止显示错误消息。-b
(或--byte-offset
): 显示匹配行的字节偏移量。-m NUM
(或--max-count=NUM
): 在找到 NUM 个匹配行后停止搜索。-A NUM
(或--after-context=NUM
): 显示匹配行之后 NUM 行。-B NUM
(或--before-context=NUM
): 显示匹配行之前 NUM 行。-C NUM
(或--context=NUM
): 显示匹配行之前和之后 NUM 行。-e PATTERN
: 指定多个搜索模式。例如,grep -e "pattern1" -e "pattern2" file.txt
。-f FILE
(或--file=FILE
): 从文件中读取搜索模式,每行一个模式。--color[=WHEN]
: 高亮显示匹配的部分。WHEN
可以是always
、auto
或never
。-E
(或--extended-regexp
): 使用扩展正则表达式。-F
(或--fixed-strings
): 将PATTERN
解释为固定字符串,而不是正则表达式。-P
(或--perl-regexp
): 使用 Perl 兼容的正则表达式(PCRE)。-d ACTION
(或--directories=ACTION
): 指定如何处理目录。ACTION
可以是read
(默认)、skip
或recurse
。-exclude=GLOB
: 跳过文件名匹配 GLOB 模式的文件或目录。-exclude-dir=DIR
: 在递归搜索中,排除 DIR 目录。
模式 (PATTERN)
- 普通字符串: 例如,
grep "hello" file.txt
。 - 正则表达式: 例如,
grep "^[0-9]" file.txt
匹配以数字开头的行。grep -E "pattern1|pattern2" file.txt
匹配包含 “pattern1” 或 “pattern2” 的行(使用扩展正则表达式)。
正则表达式中的特殊字符
.
(点):匹配任意单个字符(除了换行符)。*
(星号):匹配前一个字符零次或多次。+
(加号):匹配前一个字符一次或多次(需要-E
选项)。?
(问号):匹配前一个字符零次或一次(需要-E
选项)。[]
(字符类):匹配方括号中的任意一个字符。 例如,[abc]
匹配 “a”、“b” 或 “c”。[^]
(否定字符类):匹配不在方括号中的任意一个字符。 例如,[^abc]
匹配除了 “a”、“b” 和 “c” 之外的任意字符。^
(脱字符):匹配行首。 在字符类中表示否定。$
(美元符号):匹配行尾。\
(反斜杠):转义特殊字符,使其失去特殊含义。 例如,\.
匹配字面上的点字符。\|
(管道符):表示或(需要-E
选项)。 例如,foo\|bar
匹配 “foo” 或 “bar”。()
(圆括号):用于分组和捕获匹配的子字符串(需要-E
选项)。{}
(花括号):用于指定匹配次数的范围(需要-E
选项)。 例如,a{2,4}
匹配 “a” 出现 2 到 4 次。\b
:匹配单词边界。\w
:匹配单词字符(字母、数字和下划线)。\s
:匹配空白字符(空格、制表符等)。\d
:匹配数字(某些grep
版本支持,或者使用[0-9]
)。\<
:匹配单词的开头(某些grep
版本支持)。\>
:匹配单词的结尾(某些grep
版本支持)。
退出状态码
0
: 找到匹配的行。1
: 没有找到匹配的行。2
: 发生错误。
示例
-
在文件
file.txt
中搜索包含 “hello” 的行:1
grep "hello" file.txt
-
在文件
file.txt
中搜索包含 “hello” 的行,忽略大小写:1
grep -i "hello" file.txt
-
在文件
file.txt
中搜索不包含 “hello” 的行:1
grep -v "hello" file.txt
-
在文件
file.txt
中搜索以数字开头的行:1
grep "^[0-9]" file.txt
-
在文件
file.txt
中搜索以 “hello” 结尾的行:1
grep "hello$" file.txt
-
在文件
file.txt
中搜索完整的单词 “hello”:1
grep -w "hello" file.txt
-
递归搜索当前目录下所有文件中包含 “hello” 的行:
1
grep -r "hello" .
-
只显示包含 “hello” 的文件名:
1
grep -l "hello" *
-
显示匹配行及其行号:
1
grep -n "hello" file.txt
-
显示匹配行之前的 2 行:
1
grep -B 2 "hello" file.txt
-
显示匹配行之后的 2 行:
1
grep -A 2 "hello" file.txt
-
显示匹配行前后各 2 行:
1
grep -C 2 "hello" file.txt
-
统计包含 “hello” 的行数:
1
grep -c "hello" file.txt
-
从文件中读取搜索模式:
1
grep -f patterns.txt file.txt
-
使用扩展正则表达式搜索包含 “foo” 或 “bar” 的行:
1
grep -E "foo|bar" file.txt
-
管道中使用 grep:
1
ls -l | grep "file.txt"
注意事项
grep
默认区分大小写。- 如果
PATTERN
包含空格或其他特殊字符,最好用引号括起来。 - 正则表达式是
grep
的重要组成部分,需要熟练掌握。 - 不同版本的
grep
在正则表达式的支持上可能有所差异。GNU grep 提供了更强大的正则表达式功能。 - 使用 Shell 变量:如果想在
grep
命令中使用 Shell 变量,要使用双引号""
,这样 Shell 变量会被展开。 如果使用单引号,则变量不会被展开,而是会被当做普通字符串。 grep --help
可以查看grep
的帮助信息。
sed
sed 是一个文本处理工具,用于在命令行中对文件中的文本进行修改。它的输入可以是文件,也可以从管道读取数据
基本结构
|
|
sed
: 调用 sed 命令。'command'
: 要执行的 sed 命令。 命令用单引号括起来。-e 'command'
: 允许指定多个命令。-f scriptfile
: 从文件中读取命令。文件名
: 要处理的文件名。 如果省略,则 sed 从标准输入读取数据。
常用命令
s/regexp/replacement/flags
(替换):s
: 表示替换命令。regexp
: 正则表达式,匹配要替换的内容。replacement
: 替换后的内容。flags
: 可选的标志:g
: 全局替换,替换所有匹配项,而不是只替换第一个。i
: 忽略大小写。w 文件名
: 将替换结果写入指定的文件。1
,2
, …,9
: 只替换第 N 个匹配项。
d
(删除):删除行。a text
(追加):在当前行之后追加文本。i text
(插入):在当前行之前插入文本。c text
(更改):将当前行替换为文本。p
(打印):打印当前行(通常与-n
选项一起使用,用于抑制默认输出)。n
(下一行):读取下一行,然后执行命令。q
(退出):退出 sed。r 文件名
(读取):将指定文件的内容追加到当前行之后。w 文件名
(写入):将匹配的行写入指定的文件。y/source/dest/
(转换):将source
中的字符转换为dest
中对应的字符(类似于tr
命令)。=
(行号):打印行号。!
(非):反转选择的含义。 例如,sed '/pattern/!d' file
删除所有不匹配pattern
的行。{ }
(分组):将多个命令组合在一起。
地址 (Addresses)
地址用于指定命令作用的行。 地址可以是:
- 行号: 例如,
10
表示第 10 行。 $
: 最后一行。- 正则表达式: 例如,
/pattern/
表示匹配pattern
的行。 - 范围:
行号1,行号2
: 从行号 1 到行号 2 的范围(包括这两行)。/pattern1/,/pattern2/
: 从匹配pattern1
的行到匹配pattern2
的行(包括这两行)。行号,/pattern/
: 从指定行号到匹配pattern
的行。/pattern/,行号
: 从匹配pattern
的行到指定行号。
如果省略地址,则命令作用于所有行。
常用选项
-n
(安静模式):抑制默认输出(只打印由p
命令显式打印的行)。-i[SUFFIX]
(原地编辑):直接修改文件内容。SUFFIX
是可选的备份文件名后缀。 例如,sed -i.bak 's/foo/bar/g' file.txt
会将file.txt
中所有的 “foo” 替换为 “bar”,并将原始文件备份为file.txt.bak
。 重要提示: 使用-i
选项要小心,因为这会永久更改文件。 不加 SUFFIX 会直接修改,不做备份,更要小心。-e script
(多命令):允许在命令行中指定多个命令。-f scriptfile
(脚本文件):从文件中读取命令。-r
(扩展正则表达式):使用扩展正则表达式,例如可以使用+
,?
,|
等元字符。 (GNU sed)-E
(扩展正则表达式): 与-r
效果相同,POSIX 标准。(BSD sed, macOS)
示例
-
将文件
file.txt
中所有的 “foo” 替换为 “bar”,并打印到标准输出:1
sed 's/foo/bar/g' file.txt
-
将文件
file.txt
中所有的 “foo” 替换为 “bar”,并直接修改文件:1
sed -i 's/foo/bar/g' file.txt
-
将文件
file.txt
中所有的 “foo” 替换为 “bar”,并备份原始文件为file.txt.bak
:1
sed -i.bak 's/foo/bar/g' file.txt
-
删除文件
file.txt
中的所有空行:1
sed '/^$/d' file.txt
-
打印文件
file.txt
的第 10 行:1
sed -n '10p' file.txt
-
打印文件
file.txt
中包含 “error” 的行:1
sed -n '/error/p' file.txt
-
删除文件
file.txt
中从包含 “start” 的行到包含 “end” 的行:1
sed '/start/,/end/d' file.txt
-
在文件
file.txt
的每一行之后追加 “—”:1
sed 'a ---' file.txt
-
将文件
file.txt
中的前 10 行写入output.txt
:1
sed '1,10w output.txt' file.txt
-
将文件
file.txt
中的所有小写字母转换为大写字母:1
sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' file.txt
-
删除文件
file.txt
中的注释行(以#
开头的行):1
sed '/^#/d' file.txt
-
使用多个命令将文件
file.txt
中的 “foo” 替换为 “bar”,并将 “hello” 替换为 “world”:1
sed -e 's/foo/bar/g' -e 's/hello/world/g' file.txt
-
从脚本文件
script.sed
中读取命令:1
sed -f script.sed file.txt
-
仅替换每行中第一次出现的"foo" 为 “bar”
1
sed 's/foo/bar/' file.txt
-
替换每行中第三次出现的"foo" 为 “bar”
1
sed 's/foo/bar/3' file.txt
正则表达式中的特殊字符
.
(点):匹配任意单个字符(除了换行符)。*
(星号):匹配前一个字符零次或多次。+
(加号):匹配前一个字符一次或多次(扩展正则表达式,需要-r
或-E
选项)。?
(问号):匹配前一个字符零次或一次(扩展正则表达式,需要-r
或-E
选项)。[]
(字符类):匹配方括号中的任意一个字符。 例如,[abc]
匹配 “a”、“b” 或 “c”。[^]
(否定字符类):匹配不在方括号中的任意一个字符。 例如,[^abc]
匹配除了 “a”、“b” 和 “c” 之外的任意字符。^
(脱字符):匹配行首。 在字符类中表示否定。$
(美元符号):匹配行尾。\
(反斜杠):转义特殊字符,使其失去特殊含义。 例如,\.
匹配字面上的点字符。\|
(管道符):表示或(扩展正则表达式,需要-r
或-E
选项)。 例如,foo\|bar
匹配 “foo” 或 “bar”。()
(圆括号):用于分组和捕获匹配的子字符串。 捕获的子字符串可以在replacement
中使用\1
,\2
等引用。{}
(花括号):用于指定匹配次数的范围。 例如,a{2,4}
匹配 “a” 出现 2 到 4 次。\b
:匹配单词边界。\w
:匹配单词字符(字母、数字和下划线)。\s
:匹配空白字符(空格、制表符等)。\d
:匹配数字。 (某些sed
版本支持)\<
:匹配单词的开头。\>
:匹配单词的结尾。
注意事项
sed
默认不会修改原始文件,而是将处理结果输出到标准输出。 使用-i
选项可以修改原始文件。- 正则表达式是
sed
的重要组成部分,需要熟练掌握。 - 使用
-i
选项时要小心,最好先备份文件。 - 不同版本的
sed
在正则表达式的支持上可能有所差异。 GNU sed 提供了更强大的正则表达式功能。 - 使用 Shell 变量:如果想在
sed
命令中使用 Shell 变量,要使用双引号""
,这样 Shell 变量会被展开。 如果使用单引号,则变量不会被展开,而是会被当做普通字符串。
awk
awk 是一种文本处理工具,主要用于从文本文件中提取数据并进行格式化输出。 它是一种编程语言,允许你编写脚本来处理文本数据。 awk
逐行读取输入文件,将每一行分割成字段,然后根据你定义的规则对这些字段进行处理。
好的,以下是 awk 的基本语法和常用特性:
基本结构
|
|
awk
: 调用 awk 命令。'pattern { action }'
: 这是 awk 的程序,用单引号括起来。pattern
: 一个条件表达式(可选)。 如果省略,则对每一行都执行action
。pattern
可以是:- 正则表达式:
/regex/
- 比较表达式:
NR == 2
,$1 > 10
- 范围模式:
/start/, /end/
- 组合模式:
pattern1 && pattern2
,pattern1 || pattern2
,!pattern
- 正则表达式:
{ action }
: 要执行的动作。action
可以包含一个或多个语句,用分号分隔。 如果省略,则默认动作为print $0
(打印整行)。
file(s)
: 要处理的一个或多个文件名(可选)。 如果省略,则 awk 从标准输入读取数据。
动作 (Actions)
一些常用的 actions:
print
: 打印。print $0
: 打印整行。print $1
: 打印第一个字段。print $1, $2
: 打印第一个和第二个字段,用 OFS 分隔 (默认空格)。print "Hello", $1
: 打印字符串 “Hello” 和第一个字段,用 OFS 分隔。
printf
: 格式化打印,类似于 C 语言的printf
。printf "%s %d\n", $1, $2
: 打印第一个字段(字符串)和第二个字段(整数),并换行。
- 赋值: 给变量赋值。
count = count + 1
name = $1
- 控制流语句:
if (condition) { statements } else { statements }
for (i = 1; i <= NF; i++) { statements }
while (condition) { statements }
do { statements } while (condition)
break
continue
exit
next
: 跳过当前行,处理下一行。delete array[index]
: 删除数组元素。
字段和记录
- 字段: 每一行被分割成多个字段,默认分隔符是空格或制表符。
$1
: 第一个字段。$2
: 第二个字段。$NF
: 最后一个字段 (NF
是字段数)。$0
: 整行记录。
- 记录: 每一行被称为一个记录。
- FS (Field Separator): 字段分隔符,默认是空格或制表符。 可以用
-F
选项或在BEGIN
块中设置。 - RS (Record Separator): 记录分隔符,默认是换行符。
- OFS (Output Field Separator): 输出字段分隔符,默认是空格。
- ORS (Output Record Separator): 输出记录分隔符,默认是换行符。
- NF (Number of Fields): 当前记录的字段数。
- NR (Number of Records): 当前记录的行号 (从 1 开始)。
模式 (Patterns)
- 正则表达式:
/pattern/
: 匹配包含pattern
的行。$1 ~ /pattern/
: 匹配第一个字段包含pattern
的行。$1 !~ /pattern/
: 匹配第一个字段不包含pattern
的行。
- 比较表达式:
NR == 2
: 匹配第二行。$1 > 10
: 匹配第一个字段大于 10 的行。$2 == "abc"
: 匹配第二个字段等于 “abc” 的行。
- 范围模式:
/start/, /end/
: 匹配从包含start
的行到包含end
的行(包括这两行)。
- 组合模式:
$1 > 10 && $2 < 20
: 匹配第一个字段大于 10 并且第二个字段小于 20 的行。$1 == "a" || $2 == "b"
: 匹配第一个字段等于 “a” 或者第二个字段等于 “b” 的行。!($1 == "c")
: 匹配第一个字段不等于 “c” 的行。
BEGIN
和END
块:BEGIN { actions }
: 在处理任何输入之前执行actions
。END { actions }
: 在处理完所有输入之后执行actions
。
变量
- 内置变量:
FS
,RS
,OFS
,ORS
,NF
,NR
(前面已介绍)FILENAME
: 当前文件名。FNR
: 当前文件中的行号。ARGC
: 命令行参数的数量。ARGV
: 命令行参数数组。
- 用户自定义变量: 变量名以字母开头,可以包含字母、数字和下划线。
数组
array[index] = value
- 可以用字符串作为数组索引 (关联数组)。
for (index in array) { ... }
: 遍历数组。delete array[index]
: 删除数组元素。
函数
-
内置函数:
- 字符串函数:
length()
,substr()
,index()
,split()
,tolower()
,toupper()
- 数学函数:
sqrt()
,sin()
,cos()
,rand()
,srand()
- 时间函数:
systime()
,strftime()
- 字符串函数:
-
用户自定义函数:
1 2 3 4
function function_name(parameter1, parameter2, ...) { statements return value # 可选 }
示例
-
打印每一行的第一个字段:
1
awk '{print $1}' file.txt
-
打印第二行:
1
awk 'NR == 2' file.txt
-
打印所有包含 “error” 的行:
1
awk '/error/' file.txt
-
打印第一个字段大于 10 的行的第二个字段:
1
awk '$1 > 10 {print $2}' file.txt
-
统计文件中所有行的字段总数:
1
awk '{sum += NF} END {print sum}' file.txt
-
使用逗号作为字段分隔符,并打印每行的第一个和第三个字段:
1
awk -F',' '{print $1, $3}' file.txt
-
在处理文件之前设置字段分隔符,并在处理完文件后打印总行数:
1
awk 'BEGIN {FS = ","} {print $1} END {print "Total lines:", NR}' file.txt
-
将所有行的第一个字段转换为大写:
1
awk '{ $1 = toupper($1); print $0 }' file.txt
更详细的说明
- 可以参考 GNU Awk 用户手册:https://www.gnu.org/software/gawk/manual/gawk.html
- 很多在线教程和示例,搜索 “awk tutorial” 就能找到。