text processing
1. cat
:连接文件并打印到标准输出
cat
(concatenate) 命令是最基本也是最常用的文本命令之一。它主要用于显示文件内容,但其核心功能是连接(concatenate)文件流。
- 核心功能:
cat
读取一个或多个文件,然后将其内容按顺序输出到标准输出(通常是你的终端)。 - 基本用法:
cat <文件>
: 显示单个文件的内容。- 示例:
cat /etc/passwd
- 示例:
cat <文件1> <文件2>
: 连接两个或多个文件的内容并显示。- 示例:
cat file1.txt file2.txt
- 示例:
cat > <文件>
: 创建一个新文件并向其中写入内容。你输入的所有内容都会被重定向到文件中,直到你按下Ctrl+D
(表示文件结束)。- 示例:
cat > new_file.txt
(输入内容,然后按Ctrl+D
)
- 示例:
cat >> <文件>
: 将内容追加到一个现有文件。- 示例:
cat >> existing_file.txt
(输入内容,然后按Ctrl+D
)
- 示例:
- 常用选项及实际应用:
-n
(show number lines): 显示文件内容时,在每行前面加上行号。- 用途: 在查看代码、配置文件或日志时,方便引用特定行。
- 示例:
cat -n /etc/fstab
-b
(number non-blank lines): 类似于-n
,但只对非空行进行编号。空行不会有行号。- 用途: 当文件中有很多空行时,使行号显示更清晰。
- 示例:
cat -b my_script.sh
-s
(squeeze blank lines): 压缩连续的空行,将多行空行显示为一行空行。- 用途: 提高长日志或配置文件中内容的可读性。
- 示例:
cat -s messy_log.txt
-v
(show non-printing characters): 显示非打印字符(如制表符、回车符等)的可视化表示。- 用途: 调试文件格式问题,例如文件编码或隐藏字符。
- 示例:
cat -v binary_file
(可能显示乱码,但会标示出特殊字符)
-A
(show All): 等同于-vET
。显示所有非打印字符,包括行尾的$
符号(表示回车符),制表符显示为^I
。- 用途: 非常全面地检查文件中的隐藏字符和格式。
- 示例:
cat -A config.ini
- 使用场景与最佳实践:
- 快速查看小文件:
cat
最适合快速查看内容较短的文件。 - 文件重定向:
cat file > another_file
是一种将一个文件内容复制到另一个文件的方法。 - 管道输入:
cat
经常与其他命令结合使用,作为管道的起点,例如cat access.log | grep "error"
。 - 避免滥用
cat
: 对于大型文件,直接使用cat
会将整个文件内容倾泻到终端,这会非常低效且难以阅读。在这种情况下,应该使用分页器,如less
或more
。- 错误示例:
cat huge_log_file.log
(不推荐) - 正确示例:
less huge_log_file.log
或cat huge_log_file.log | less
- 错误示例:
- 快速查看小文件:
cat
简单而强大,是你文本处理旅程的起点。
2. less
:交互式文件内容查看器
less
是一个分页器,用于逐页或逐行地查看文件内容。它是 cat
命令的重要补充,特别适合查看大文件,因为它不会一次性加载整个文件,而是按需加载,效率更高。
- 核心功能:
less
允许你以交互方式向前或向后滚动文件,搜索文本,并且在不将整个文件加载到内存的情况下查看其内容。它在查看大日志文件、大型配置文件或任何你不想一次性显示到终端的文本时非常有用。 - 基本用法:
less <文件>
: 打开文件进行交互式查看。- 示例:
less /var/log/syslog
- 示例:
command | less
: 作为管道的消费者,接收其他命令的输出并分页显示。- 示例:
ls -lR / | less
(递归列出文件,然后分页查看)
- 示例:
- 交互式导航键(进入
less
后使用):Space
或f
: 向前翻一页。b
: 向后翻一页。Enter
或j
: 向前滚动一行。k
: 向后滚动一行。G
(大写): 跳到文件末尾。g
(小写): 跳到文件开头。/ <模式>
: 向前搜索指定的文本模式(区分大小写)。- 示例:
/error
(搜索 “error”)
- 示例:
? <模式>
: 向后搜索指定的文本模式。n
: 重复上一次搜索(向下)。N
: 重复上一次搜索(向上)。q
: 退出less
。h
: 显示帮助信息(所有可用快捷键)。
- 常用选项及实际应用:
-N
(show line Numbers): 在每行前面显示行号。- 用途: 方便定位日志或代码中的特定行。
- 示例:
less -N /etc/apache2/apache2.conf
-S
(chop long lines): 截断(而不是换行)过长的行。- 用途: 在终端显示日志或结构化数据时,避免长行导致混乱的换行。
- 示例:
less -S complex_log.txt
+F
(follow mode): 进入“追踪模式”,类似于tail -f
。当文件有新内容写入时,less
会自动滚动到文件末尾显示新内容。- 用途: 实时监控不断增长的日志文件。
- 使用方法: 进入
less
后按Shift+f
也可以进入此模式,按Ctrl+c
退出追踪模式回到常规查看。 - 示例:
less +F /var/log/auth.log
-R
(raw control characters): 显示原始控制字符(如颜色代码)。这对于查看带有颜色输出的日志文件(如journalctl
的输出)非常有用。- 用途: 保留彩色日志的显示效果。
- 示例:
journalctl -f | less -R
-i
(ignore case in search): 搜索时忽略大小写。- 示例:
less -i logfile.txt
(然后/Error
会匹配 “error”, “Error”, “ERROR” 等)
- 示例:
less
vs.more
:less
是more
的一个改进版本。less
允许你向前和向后滚动(因此叫做 “less is more”),而more
通常只能向前滚动。在现代 Linux 系统中,less
几乎完全取代了more
。
less
是日常 Linux 管理和故障排除中不可或缺的工具。掌握其导航和搜索功能,将极大提升你处理大型文本文件的效率。
3. head
:显示文件头部
head
命令用于显示文件或管道输出的开头部分。
- 核心功能: 默认情况下,
head
显示文件的前 10 行。 - 基本用法:
head <文件>
: 显示文件的前 10 行。- 示例:
head /var/log/syslog
- 示例:
command | head
: 显示命令输出的前 10 行。- 示例:
ls -l /bin | head
- 示例:
- 常用选项及实际应用:
-n <行数>
或-<行数>
: 显示指定行数的内容。- 用途: 精确控制要查看的行数,常用于快速预览文件的开头。
- 示例:
head -n 5 my_config.ini
(显示前 5 行)
-c <字节数>
: 显示文件的前指定字节数的内容。- 用途: 检查文件的编码或快速查看文件头部二进制信息。
- 示例:
head -c 100 image.jpg
(显示图片文件的前 100 字节)
- 实际应用场景:
- 快速预览: 快速查看日志文件的最新记录或配置文件开头的注释。
- 与管道结合: 从其他命令的输出中提取前几行进行处理。
- 示例:
ps aux | head -n 1
(只显示ps
命令的标题行)
- 示例:
4. tail
:显示文件尾部
tail
命令用于显示文件或管道输出的末尾部分。它与 head
相对,主要用于查看文件的最新内容,尤其是在监控日志文件时。
- 核心功能: 默认情况下,
tail
显示文件的最后 10 行。 - 基本用法:
tail <文件>
: 显示文件的最后 10 行。- 示例:
tail /var/log/nginx/access.log
- 示例:
command | tail
: 显示命令输出的最后 10 行。- 示例:
history | tail
(显示最近执行的 10 条命令)
- 示例:
- 常用选项及实际应用:
-n <行数>
或-<行数>
: 显示指定行数的内容。- 用途: 精确控制要查看的行数。
- 示例:
tail -n 20 error.log
(显示最后 20 行错误日志)
-f
(follow): 持续监控文件内容。 这是tail
最强大和最常用的功能之一。当文件有新内容写入时,tail -f
会实时地将新内容打印到终端,而无需你重新执行命令。- 用途: 实时监控正在增长的日志文件,是系统管理员和开发人员的必备工具。
- 中断: 按
Ctrl+C
退出tail -f
。 - 示例:
tail -f /var/log/syslog
(实时监控系统日志)
-F
(follow by name): 类似于-f
,但更健壮。如果被监控的文件被重命名、删除然后重建(这在日志轮换时很常见),-F
会检测到这种变化并继续追踪新文件,而-f
可能会停止追踪。- 用途: 监控那些会被日志轮换处理的日志文件,确保不中断追踪。
- 示例:
tail -F /var/log/nginx/access.log
-c <字节数>
: 显示文件的最后指定字节数的内容。- 用途: 检查文件的尾部二进制信息。
- 示例:
tail -c 50 my_binary_output
- 实际应用场景:
- 实时日志监控: 使用
tail -f
监控 Web 服务器、数据库或应用程序的日志,以便立即发现错误或异常。 - 审计日志: 快速查看系统安全日志的最新条目。
- 查看大文件末尾: 在文件非常大时,不想加载整个文件,只想查看最新的记录。
- 实时日志监控: 使用
tail
特别是其 -f
或 -F
选项,是 Linux 运维人员和开发人员的每日利器,对于实时故障排除和系统健康监控至关重要。
5. sort
:对文本文件内容进行排序
sort
命令是一个功能强大的工具,用于对文本文件中的行进行排序。它能根据不同的标准(如字母顺序、数字大小、月份等)重新排列文本行,这在数据整理、日志分析和报告生成中非常有用。
- 核心功能:
sort
读取输入的每一行,然后根据指定的规则对这些行进行排序,并将排序后的结果输出到标准输出。 - 基本用法:
sort <文件>
: 对文件内容按字母顺序(默认升序)进行排序。- 示例:
sort names.txt
- 示例:
command | sort
: 对其他命令的输出进行排序。- 示例:
ls -l | sort
(按文件名进行排序)
- 示例:
- 常用选项及实际应用:
-r
(reverse): 反向排序(降序)。- 用途: 获取按相反顺序排列的结果,例如按数字从大到小。
- 示例:
sort -r numbers.txt
-n
(numeric sort): 按数值大小排序。这非常重要,因为默认的排序是基于字符串的字典顺序,这意味着 “10” 在 “2” 之前,但数值排序会正确地将 “2” 放在 “10” 之前。- 用途: 对包含数字的数据进行正确排序。
- 示例:
sort -n scores.txt
(scores.txt: 10, 2, 5 -> 2, 5, 10)
-k <字段号>
(key): 指定排序的键(字段)。当一行有多个字段(例如,用空格或制表符分隔)时,你可以指定根据哪个字段进行排序。字段从 1 开始计数。- 用途: 对表格或结构化数据进行复杂排序。
- 示例: 假设
data.txt
内容是apple 10\nbanana 5\norange 8
sort -k 2n data.txt
: 按第二个字段的数值大小排序。banana 5
orange 8
apple 10
-t <分隔符>
(field terminator): 指定字段分隔符。默认分隔符是空格。如果你想用其他字符(如逗号,
或冒号:
)作为字段分隔符,就需要使用此选项。- 用途: 处理 CSV 或
/etc/passwd
等以特定字符分隔的数据。 - 示例: 假设
users.csv
内容是john,doe,1001\nalice,smith,1000
sort -t',' -k 3n users.csv
: 以逗号为分隔符,按第三个字段的数值大小排序。alice,smith,1000
john,doe,1001
- 用途: 处理 CSV 或
-u
(unique): 只输出唯一的行。如果有多行内容完全相同,sort -u
只会保留其中一行。- 用途: 去除重复行,生成唯一列表。
- 示例:
sort -u duplicate_list.txt
-f
(fold case): 排序时忽略大小写。例如,Apple
和apple
会被视为相同。- 用途: 进行不区分大小写的字典排序。
- 示例:
sort -f mixed_case_names.txt
-M
(month sort): 按月份名称排序。它能识别英文月份缩写(Jan, Feb等)。- 用途: 对包含月份名称的日志或数据进行排序。
- 示例:
sort -M monthly_data.txt
(其中包含 ‘Jan’, ‘Feb’ 等行)
-V
(version sort): 按版本号排序。例如,它能正确排序file-1.10
在file-1.9
之后。- 用途: 对软件版本号列表进行排序。
- 示例:
sort -V software_versions.txt
(software_versions.txt: v1.10, v1.2, v1.9 -> v1.2, v1.9, v1.10)
- 实际应用场景:
- 日志分析: 将日志文件按时间戳排序,或按错误代码、IP 地址排序。
- 数据整理: 对 CSV 文件按某一列进行排序,方便后续处理或分析。
- 生成报告: 对统计数据进行排序,生成可读性更高的报告。
- 去重: 结合
-u
选项去除重复的数据行。
sort
是 Linux 文本处理工具链中不可或缺的一环。掌握其各种排序方式和选项,将极大地提高你处理和分析结构化文本数据的能力。
6. wc
:统计字数、行数和字符数
wc
(word count) 命令用于统计给定文件或标准输入的行数、单词数和字节数(或字符数)。这是一个非常基础但极其常用的工具,尤其在需要快速获取文本概览或在脚本中进行数据统计时。
- 核心功能:
wc
默认会输出文件的行数、单词数和字节数。 - 基本用法:
wc <文件>
: 统计单个文件的行数、单词数和字节数。- 示例:
wc document.txt
- 输出示例:
10 50 300 document.txt
(10行,50个单词,300个字节,文件名)
- 示例:
command | wc
: 统计其他命令输出的行数、单词数和字节数。- 示例:
ls -l | wc -l
(统计ls -l
命令输出的行数,即文件/目录的数量)
- 示例:
wc <文件1> <文件2>
: 统计多个文件的总行数、单词数和字节数,并单独列出每个文件的统计。- 示例:
wc file1.txt file2.txt
- 示例:
- 常用选项及实际应用:
-l
(count lines): 只统计行数。 这是最常用的选项之一,在需要快速知道文件有多少行或某个命令输出了多少条记录时非常方便。- 用途: 统计日志文件有多少条记录、代码文件有多少行、命令输出的条目数量等。
- 示例:
wc -l access.log
(统计访问日志文件中的请求数量) - 示例:
find . -type f | wc -l
(统计当前目录及其子目录下有多少个文件)
-w
(count words): 只统计单词数。- 用途: 统计文章、文档或文本文件中单词的总数。单词通常由空格、制表符或换行符分隔。
- 示例:
wc -w essay.txt
-c
(count characters/bytes): 只统计字节数。 在大多数情况下,对于 ASCII 文本文件,一个字节对应一个字符。但对于多字节字符编码(如 UTF-8),一个字符可能由多个字节组成。- 用途: 获取文件大小的粗略估计,或者在处理单字节编码文本时统计字符数。
- 示例:
wc -c image.jpg
(显示图片文件的字节大小)
-m
(count multibyte characters): 只统计字符数(考虑多字节字符)。 对于 UTF-8 等多字节编码文件,这个选项会正确统计实际的字符数量,而不是字节数量。- 用途: 准确统计包含非 ASCII 字符(如中文、日文等)的文本文件中的字符数量。
- 示例:
wc -m unicode_text.txt
- 实际应用场景:
- 日志分析: 快速查看日志文件每天新增了多少行(记录)。
- 代码统计: 统计项目中的代码行数(结合
find
或grep
)。 - 脚本自动化: 在脚本中判断文件是否为空(
wc -l file | awk '{print $1}'
是否为 0),或控制循环次数。 - 资源监控: 监控生成文件的大小或行数变化。
wc
是一款小巧但功能强大的工具,它是 Linux 文本处理流程中用于快速量化信息的关键环节。
7. tr
:字符转换或删除
tr
(translate or delete characters) 是一个专门用于转换或删除字符的命令行工具。它非常适合处理单个字符级别的替换或清理。
核心功能:
tr
从标准输入读取字符流,根据你指定的规则将字符进行转换(替换)或删除,然后将结果输出到标准输出。它不处理文件,而是处理字符流,所以通常与管道符|
结合使用。不支持正则表达式。基本用法:
tr <SET1> <SET2>
: 将SET1
中匹配的字符替换为SET2
中对应位置的字符。SET1
和SET2
通常是字符集或字符范围。- 示例:
echo "hello world" | tr 'a-z' 'A-Z'
(将所有小写字母转换为大写)- 输出:
HELLO WORLD
- 输出:
- 示例:
tr -d <SET1>
: 删除SET1
中匹配的所有字符。- 示例:
echo "hello 123 world" | tr -d '0-9'
(删除所有数字)- 输出:
hello world
- 输出:
- 示例:
常用选项及实际应用:
-c
(complement) 补码 字符集补集,类似非SET1
的字符集echo '#$%abc 123'| tr -dc 'a-z0-9'
删除除数字字母以外所有字符。
-d
(delete): 删除SET1
中出现的所有字符。SET2
在此模式下通常不使用。- 用途: 清理文本中的特定字符,如删除标点符号、数字或空白字符。
- 示例:
cat names.txt | tr -d ' '
(删除names.txt
中的所有空格) - 示例:
echo "remove\rwindows\nnewlines\r" | tr -d '\r'
(删除 Windows 风格的回车符\r
)
-s
(squeeze-repeats): 压缩重复的字符。当SET1
中的字符连续出现时,将其替换为单个实例。- 用途: 清理文本中多余的空白字符(如多个空格、多个换行符),使文本更整洁。
- 示例:
echo "this is a test" | tr -s ' '
(将多个连续空格压缩为单个空格)- 输出:
this is a test
- 输出:
- 示例:
cat messy.txt | tr -s '\n'
(将文件中连续的多行空行压缩为单行空行)
字符集和范围:
'a-z'
或'A-Z'
或'0-9'
:匹配指定范围内的所有字符。[:lower:]
、[:upper:]
、[:alpha:]
、[:digit:]
、[:alnum:]
、[:space:]
、[:punct:]
等:预定义的字符类。- 示例:
echo "Hello World123!" | tr '[:lower:]' '[:upper:]'
(小写转大写) - 示例:
echo "Line One\n\n\nLine Two" | tr -s '[:space:]'
(压缩所有空白字符,包括空格、制表符、换行等)
- 示例:
实际应用场景:
- 格式转换: 快速进行大小写转换、换行符转换(例如将 Unix 换行符
\n
转换为 Windows 风格\r\n
,或反之)。 - 数据清洗: 移除不必要的字符,如标点、数字、特殊符号。
- 字符替换: 将旧的字符替换为新的字符。
- 简单加密/解密: 使用字符偏移进行简单的替换密码(如凯撒密码)。
- 格式转换: 快速进行大小写转换、换行符转换(例如将 Unix 换行符
tr
是一个非常精巧的工具,它在字符级别的文本转换和清理方面表现出色,是管道操作中的得力助手。
8. cut
:按列提取文本
cut
命令用于从文件或标准输入的每一行中提取指定的部分(列或字段)。它非常适合处理结构化的、以特定分隔符分隔的数据,例如 CSV 文件或命令的表格输出。
- 核心功能:
cut
接收一个输入流,然后根据字符位置、字节位置或字段分隔符,提取每一行中你感兴趣的部分。 - 基本用法:
cut -d <分隔符> -f <字段列表> <文件>
: 根据分隔符提取字段。- 示例:
cut -d':' -f1 /etc/passwd
(以冒号:
为分隔符,提取/etc/passwd
文件的第一个字段,即用户名)
- 示例:
cut -c <字符范围> <文件>
: 根据字符位置提取字符。- 示例:
cut -c1-5 names.txt
(提取names.txt
每行的前 5 个字符)
- 示例:
command | cut ...
: 对其他命令的输出进行提取。- 示例:
ls -l | cut -d' ' -f9
(提取ls -l
输出的第 9 个字段,通常是文件名)
- 示例:
- 常用选项及实际应用:
-d <分隔符>
(delimiter): 指定字段分隔符。默认分隔符是制表符。- 用途: 当你的数据不是以空格或制表符分隔,而是以逗号、冒号、竖线等分隔时,必须使用此选项。
- 示例:
cut -d',' -f2,4 data.csv
(以逗号为分隔符,提取第 2 和第 4 个字段)
-f <字段列表>
(fields): 指定要提取的字段编号。- 字段列表格式:
N
: 单个字段(如-f3
)N-M
: 从 N 到 M 的字段范围(如-f2-5
)N-
: 从 N 到行尾的所有字段(如-f3-
)-M
: 从行头到 M 的所有字段(如-f-4
)N,M,P
: 多个不连续的字段(如-f1,5,7
)
- 用途: 灵活地选择需要显示的数据列。
- 示例:
cut -d':' -f1,7 /etc/passwd
(提取用户名和 shell 路径)
- 字段列表格式:
-c <字符范围>
(characters): 根据字符位置提取。忽略分隔符。- 范围格式: 与
-f
类似 (N
,N-M
,N-
,-M
,N,M,P
)。 - 用途: 处理没有明确分隔符,但需要按固定宽度或位置提取的数据。
- 示例:
echo "HelloWorld" | cut -c1-5
(提取前 5 个字符Hello
)
- 范围格式: 与
--complement
(complement selected data): 反转选择,即提取所有不在指定字段/字符范围内的部分。- 用途: 删除特定列,保留其他所有列。
- 示例:
cut -d',' -f3 --complement data.csv
(删除data.csv
中的第三列,保留其他所有列)
--output-delimiter=<分隔符>
: 指定输出字段之间的分隔符。默认情况下,输出分隔符与输入分隔符相同。- 用途: 在提取字段后,改变输出的格式。
- 示例:
cut -d':' -f1,5 /etc/passwd --output-delimiter=','
(输出用户名和全名,用逗号分隔)
- 实际应用场景:
- 日志分析: 从 Web 服务器日志中提取 IP 地址、请求路径或状态码。
- CSV 处理: 从 CSV 文件中提取特定列进行分析或进一步处理。
- 命令输出解析: 配合
ls
,ps
,netstat
等命令,提取关键信息。 - 配置文件处理: 从
/etc/fstab
等文件中提取挂载点或文件系统类型。 - 数据清洗: 移除不需要的数据列。
cut
是处理列式文本数据的理想工具,它以其简洁和高效性,在日常系统管理和脚本编写中占有一席之地。
9. uniq
命令深度解析
uniq
命令(unique 的缩写)是一个非常实用的文本处理工具,它用于报告或省略文件中的重复行。它的核心功能是筛选连续的重复行。理解这一点至关重要:uniq
默认只处理相邻的重复行,而不是文件中所有位置的重复行。如果你的文件中有不相邻的重复行,你需要先使用 sort
命令进行排序。
命令语法
1 | uniq [OPTION]... [INPUT [OUTPUT]] |
INPUT
: 要处理的输入文件。如果未指定,uniq
将从标准输入读取。OUTPUT
: 结果写入的输出文件。如果未指定,结果将写入标准输出。
核心功能与使用场景
uniq
最常见的用法是:
删除连续的重复行:这是
uniq
的默认行为。1
2cat file.txt | uniq
uniq file.txt这会从
file.txt
中移除所有连续重复的行,只保留一个副本。计算连续重复行的次数:使用
-c
或--count
选项。1
cat file.txt | uniq -c
这会在每行前面添加一个计数,表示该行连续重复的次数。
只显示唯一的行(不重复的行):使用
-u
或--unique
选项。1
cat file.txt | uniq -u
这只会显示那些在文件中不与相邻行重复的行。
只显示重复的行:使用
-d
或--repeated
选项。1
cat file.txt | uniq -d
这只会显示那些连续出现多次的行(每种重复的行只显示一次)。
深入选项解析
除了上述核心功能,uniq
还提供了一些更精细的控制选项:
-i
或--ignore-case
: 忽略大小写差异进行比较。1
cat file.txt | uniq -i
这在处理包含大小写混合数据的日志文件或列表时非常有用。例如,”apple” 和 “Apple” 将被视为重复。
-s N
或--skip-chars=N
: 比较时跳过每行的前 N 个字符。1
cat file.txt | uniq -s 5
如果你有一个固定格式的数据文件,而你只想根据某一部分内容进行去重,这个选项就很有用。例如,日志文件中时间戳后面的消息内容。
-f N
或--skip-fields=N
: 比较时跳过每行的前 N 个字段。字段默认由空格分隔。1
cat file.txt | uniq -f 1
这类似于
-s
,但是是基于字段(通常是空格分隔的单词)而不是字符。例如,一个包含 “ID Name Value” 的文件,如果你想基于 “Name” 去重而忽略 “ID”,就可以跳过第一个字段。-w N
或--check-chars=N
: 只比较每行的前 N 个字符。1
cat file.txt | uniq -w 10
这在当你只关心行的特定前缀是否重复时很有用。
uniq
与 sort
的协同作用
正如开头所强调的,uniq
默认只处理连续的重复行。因此,如果你想去除文件中所有重复的行(无论它们是否相邻),你需要先使用 sort
命令对文件内容进行排序。
经典组合:
1 | sort file.txt | uniq |
这是 uniq
最常用和最强大的组合之一。sort
将所有相同的行都放到一起,然后 uniq
就可以有效地去除这些现在相邻的重复行。
示例:
假设 data.txt
内容如下:
1 | apple |
uniq data.txt
的输出将是:1
2
3
4
5apple
banana
apple
cherry
banana(没有任何变化,因为没有连续重复的行)
sort data.txt | uniq
的输出将是:1
2
3apple
banana
cherry(所有重复行都被成功去除)
实际应用场景
- 日志分析:
- 找出特定错误消息的重复次数。
- 去除日志中连续出现的重复信息,使日志更易读。
- 数据清洗:
- 从列表中移除重复的条目(例如,IP 地址、URL)。
- 处理 CSV 文件时,结合
cut
和sort
去除特定列的重复值。
- 统计分析:
- 统计某个文件中不同值的出现频率(结合
sort
和uniq -c
)。
- 统计某个文件中不同值的出现频率(结合
- 脚本编写:
- 在 shell 脚本中作为管道的一部分,用于数据预处理或后处理。
10. grep
:在文件中搜索模式
grep
(Global Regular Expression Print) 是 Linux/Unix 系统中最常用、功能也最强大的文本搜索工具之一。它能在一个或多个文件中,或者在标准输入中,查找符合指定模式(pattern,通常是正则表达式)的文本行,并打印出匹配的行。
核心功能:
grep
的核心是模式匹配。它会逐行读取输入,如果某行包含了你定义的模式,就会将这行输出。基本用法:
grep <模式> <文件>
: 在指定文件中搜索模式。- 示例:
grep "error" /var/log/syslog
(在 syslog 文件中查找包含 “error” 的行)
- 示例:
command | grep <模式>
: 在其他命令的输出中搜索模式(这是grep
最常见的用法之一)。- 示例:
ps aux | grep "apache2"
(查找所有与 apache2 相关的进程)
- 示例:
模式类型:
grep 支持三种主要的模式类型,它们提供了不同级别的正则表达式功能:
- 基本正则表达式 (BRE): 默认模式。像
.
、*
这样的特殊字符需要转义(如\.
、\*
)才能作为字面量匹配,而像?
、+
、{
、|
、(
、)
这些高级元字符则默认被视为字面量,需要转义才能作为正则表达式元字符使用。 - 扩展正则表达式 (ERE): 使用
-E
或egrep
命令。支持更丰富的正则表达式语法,如+
(一个或多个),?
(零个或一个),|
(或),()
(分组)。这些元字符无需转义。 - Perl 兼容正则表达式 (PCRE): 使用
-P
选项。提供最强大的正则表达式功能,包括回溯引用、非贪婪匹配等高级特性。但并非所有grep
版本都支持。
- 基本正则表达式 (BRE): 默认模式。像
常用选项及实际应用:
-i
(ignore case): 忽略大小写进行匹配。- 用途: 查找时不用关心大小写,例如同时匹配 “Error”、”error”、”ERROR”。
- 示例:
grep -i "warning" application.log
-v
(invert match): 反转匹配,只打印不符合模式的行。- 用途: 排除特定内容,例如过滤掉日志中的正常心跳信息,只看异常。
- 示例:
grep -v "INFO" debug.log
(显示所有不含 “INFO” 的行)
-n
(line number): 显示匹配行的行号。- 用途: 快速定位文件中匹配内容的具体位置。
- 示例:
grep -n "failed login" /var/log/auth.log
-c
(count): 只显示匹配的行数,而不是具体的行内容。- 用途: 统计某个错误或事件发生的次数。
- 示例:
grep -c "GET /admin" access.log
(统计有多少次访问了 /admin 路径)
-l
(files with matches): 只显示包含匹配行的文件名,而不是匹配的内容。- 用途: 在多个文件中快速查找哪个文件包含了特定信息。
- 示例:
grep -l "password" /etc/*
(在 /etc 目录下所有文件中查找包含 “password” 的文件)
-r
(recursive): 递归搜索,在指定目录及其所有子目录中搜索文件。- 用途: 搜索整个项目目录或日志归档目录。
- 示例:
grep -r "TODO" ./my_project/
(在my_project
目录及其子目录中查找包含 “TODO” 的文件)
-w
(word regex): 只匹配整个单词。模式必须作为一个独立的单词出现,而不是单词的一部分。- 用途: 避免误匹配,例如查找 “cat” 时只匹配单词 “cat”,而不是 “category” 或 “concatenate”。
- 示例:
grep -w "user"
-x
(line regex): 只匹配整行。模式必须与整行完全匹配。- 用途: 查找特定且完整的配置行。
- 示例:
grep -x "PermitRootLogin no" /etc/ssh/sshd_config
-A <NUM>
(After context): 显示匹配行以及它之后的NUM
行。- 用途: 查看错误发生后的上下文信息。
- 示例:
grep -A 5 "error code 500" access.log
-B <NUM>
(Before context): 显示匹配行以及它之前的NUM
行。- 用途: 查看错误发生前的上下文信息。
- 示例:
grep -B 3 "Segmentation fault" dmesg.log
-C <NUM>
(Context): 显示匹配行以及它之前和之后的NUM
行。等同于-A NUM -B NUM
。- 示例:
grep -C 2 "failed connection" syslog
- 示例:
-E
或egrep
: **使用扩展正则表达式 (ERE)**。- 用途: 当你需要使用
|
(或),+
(一个或多个),?
(零个或一个) 等高级正则元字符时,无需转义。 - 示例:
grep -E "Error|Warning" application.log
(匹配包含 “Error” 或 “Warning” 的行)
- 用途: 当你需要使用
-P
(Perl-compatible Regex): **使用 Perl 兼容正则表达式 (PCRE)**。- 用途: 需要更复杂的正则表达式特性,如非捕获组、前瞻断言等。
- 示例:
grep -P '(?<=prefix)\d+' file.txt
(查找前缀 “prefix” 后面跟着的数字)
实际应用场景:
- 日志分析: 过滤特定错误、警告、IP 地址、用户请求等。
- 配置文件检查: 查找特定的配置项或注释。
- 代码审查: 查找代码中的特定函数调用、变量定义或注释。
- 安全审计: 在日志中搜索可疑活动模式。
- 数据提取: 结合其他文本处理工具(如
awk
,sed
)从大文件中提取所需信息。
功能太多,……
11. sed
:流编辑器(Stream Editor)
sed
是一个非交互式的流编辑器。这意味着它一次处理一行文本,对每一行执行你指定的编辑操作,然后将修改后的行输出到标准输出。它不会改变原始文件(除非你使用重定向或特定选项),这使得它在处理大量数据时非常安全和高效。
核心功能:
sed
通过模式匹配(通常是正则表达式)和替换来对文本流进行转换。它擅长查找和替换、删除行、插入行等批处理任务。基本用法:
sed '<命令>' <文件>
: 对文件内容执行sed
命令。- 示例:
sed 's/old_text/new_text/' file.txt
(替换file.txt
中每行第一个old_text
为new_text
)
- 示例:
command | sed '<命令>'
: 对其他命令的输出执行sed
命令。- 示例:
cat access.log | sed 's/GET /POST /'
(将日志中的所有GET
请求改为POST
请求)
- 示例:
最常见的
sed
命令类型:替换 (s
)s/pattern/replacement/[flags]
pattern
: 要搜索的正则表达式。replacement
: 替换的字符串。flags
: 可选标志,用于修改替换行为。
常用选项和
s
命令的标志以及实际应用:全局替换 (g flag):
sed ‘s/pattern/replacement/g’ file.txt
- 用途: 替换一行中所有匹配的模式,而不是只替换第一个。这是最常用的标志之一。
- 示例:
sed 's/error/issue/g' app.log
(将app.log
中所有出现的 “error” 都替换为 “issue”)
不打印原行,只打印替换后的行 (-n 选项配合 p 标志):
sed -n ‘s/pattern/replacement/p’ file.txt
- 用途: 只显示那些被成功替换的行。当只想看到更改发生在哪几行时非常有用。
- 示例:
sed -n 's/user_id=\([0-9]\+\)/uid=\1/p' debug.log
(只打印包含user_id=
且被替换为uid=
的行)
忽略大小写 (i flag):
sed ‘s/pattern/replacement/i’ file.txt
- 用途: 替换时不区分大小写。
- 示例:
sed 's/fail/FAIL/gi' results.txt
(将 “fail”, “Fail”, “FAIL” 等都替换为 “FAIL”)
指定行范围的替换:
sed ‘N,Ms/pattern/replacement/‘ file.txt (N到M行)
sed ‘/pattern1/,/pattern2/s/pattern/replacement/‘ file.txt (匹配 pattern1 到 pattern2 的行范围)
- 用途: 对文件的特定部分进行修改,而不是整个文件。
- 示例:
sed '10,20s/DEBUG/INFO/' log.txt
(只替换第 10 到 20 行中的 “DEBUG” 为 “INFO”) - 示例:
sed '/^<start>/,/^<end>/s/old/new/g' config.xml
(替换<start>
和<end>
标记之间所有行的 “old” 为 “new”)
删除行 (d command):
sed ‘/pattern/d’ file.txt
- 用途: 删除匹配模式的行。
- 示例:
sed '/^#/d' config.conf
(删除以#
开头的所有注释行) - 示例:
sed '1,5d' file.txt
(删除文件的前 5 行) - 示例:
sed '$d' file.txt
(删除文件的最后一行)
插入行 (i command) / 追加行 (a command):
sed ‘/pattern/i\插入内容’ (在匹配行之前插入)
sed ‘/pattern/a\追加内容’ (在匹配行之后追加)
- 用途: 在文件中添加新的行,常用于修改配置文件。
- 示例:
sed '/^# Some setting/a\new_setting=value' config.conf
(在匹配注释行之后追加一行)
原地编辑 (-i 选项): 警告:这是一个非常有用的但有风险的选项!
sed -i ‘s/pattern/replacement/g’ file.txt
- 用途: 直接修改原始文件,而不是将结果打印到标准输出。这意味着
sed
会在幕后创建一个临时文件,将修改后的内容写入临时文件,然后用临时文件替换原始文件。 - 风险: 一旦执行,更改无法撤销。务必谨慎使用,强烈建议在使用前备份文件。
- 备份功能:
sed -i.bak 's/old/new/' file.txt
(替换的同时创建原始文件的备份file.txt.bak
)
- 用途: 直接修改原始文件,而不是将结果打印到标准输出。这意味着
正则表达式在 sed 中的应用:
sed 对正则表达式的支持是其强大的基础。熟练使用正则表达式可以让你进行极其复杂的文本转换。
实际应用场景:
- 配置文件批量修改: 快速修改多台服务器上的配置文件,例如更改端口号、数据库连接字符串等。
- 日志数据清洗: 从日志中删除不必要的行、提取特定信息或匿名化敏感数据。
- 格式转换: 将一种文本格式转换为另一种,例如 CSV 到特定分隔符的转换。
- 代码维护: 批量修改代码中的变量名、函数名或注释。
12. awk
:强大的文本分析和报告工具
awk
(或者 gawk
,GNU Awk) 是一种功能强大的文本处理语言,也是一个程序。它以其在处理列(字段)式数据方面的强大能力而闻名。awk
擅长从文件或标准输入中读取数据,根据你定义的规则对数据进行模式匹配和处理,然后生成格式化的输出。
- 核心功能:
awk
逐行读取输入,将每一行解析成由字段(列)组成。然后,它会对这些字段执行操作,这些操作由你定义的模式-动作对 (pattern { action }
) 决定。 - 基本用法:
awk 'pattern { action }' <文件>
: 对文件内容执行awk
命令。- 示例:
awk '{print $1, $3}' access.log
(打印access.log
中每一行的第一个和第三个字段)
- 示例:
command | awk 'pattern { action }'
: 对其他命令的输出执行awk
命令。- 示例:
ls -l | awk '{print $NF}'
(打印ls -l
输出的最后一列,通常是文件名)
- 示例:
awk
的核心概念:- 记录 (Record): 默认情况下,每一行输入被视为一个记录。你可以通过
RS
(Record Separator) 变量改变它。 - 字段 (Field): 每个记录被分成多个字段。默认情况下,字段由空格或制表符分隔。你可以通过
FS
(Field Separator) 变量改变它。$0
: 代表整个当前记录(整行)。$1
,$2
,$3
, …: 代表记录中的第一个、第二个、第三个字段,以此类推。NF
(Number of Fields): 内置变量,代表当前记录中的字段总数。$NF
则代表最后一个字段。NR
(Number of Records): 内置变量,代表当前处理的记录号(行号)。
- 记录 (Record): 默认情况下,每一行输入被视为一个记录。你可以通过
- 模式-动作对 (
pattern { action }
):pattern
(模式): 可选。可以是正则表达式、比较表达式(如$3 > 10
)、布尔组合,或者特殊模式BEGIN
和END
。只有当模式匹配时,才会执行相应的动作。如果省略模式,则对每一行执行动作。action
(动作): 必需。是{}
括起来的一系列命令。包括print
语句、变量赋值、算术操作、条件语句 (if
)、循环 (for
,while
) 等。
- 常用选项和操作以及实际应用:
- 指定字段分隔符 (
-F
选项或FS
变量):awk -F':' '{print $1}' /etc/passwd
: 使用冒号:
作为字段分隔符,打印/etc/passwd
文件的用户名(第一个字段)。awk 'BEGIN {FS=","} {print $2}' data.csv
: 在BEGIN
块中设置字段分隔符为逗号。
- 打印特定字段:
awk '{print $1, $4}' log.txt
: 打印log.txt
中每一行的第一个和第四个字段。
- 条件匹配和过滤:
awk '$3 > 100 {print $1}' sales.txt
: 打印sales.txt
中第三个字段值大于 100 的行的第一个字段。awk '/ERROR/ {print NR, $0}' app.log
: 查找包含 “ERROR” 的行,并打印其行号和整行内容。
- 计算和统计:
awk '{sum += $2} END {print "Total:", sum}' data.txt
: 计算data.txt
中第二列的总和。awk '{count[$1]++} END {for (name in count) print name, count[name]}' votes.txt
: 统计votes.txt
中每个名字出现的次数。
BEGIN
和END
块:BEGIN { action }
: 在awk
开始处理输入文件之前执行一次。常用于设置变量、打印标题。END { action }
: 在awk
处理完所有输入文件后执行一次。常用于汇总结果、打印页脚。- 示例:
awk 'BEGIN {print "--- Report ---"} {print $1, $2} END {print "--- End ---"}' data.txt
- 字符串操作:
length($0)
: 获取当前行长度。substr(string, start, length)
: 提取子字符串。split(string, array, separator)
: 将字符串分割成数组。gsub(regex, replacement, string)
: 全局替换字符串。
- 指定字段分隔符 (
- 实际应用场景:
- 日志解析: 从复杂的日志文件中提取特定的字段、统计错误类型、分析用户行为模式。
- 数据报告: 对表格数据进行聚合、计算平均值、总和或生成定制化的报告。
- 系统监控脚本: 提取
ps
,netstat
,df
等命令输出中的关键信息。 - 配置文件处理: 查找特定参数、修改参数值或添加/删除配置行(虽然
sed
更直接,但awk
可以在更复杂的逻辑下完成)。 - 数据清洗: 过滤掉不符合条件的行,或者重新格式化数据。
awk
是一门小型的编程语言,它的灵活性和强大功能使其成为 Linux 文本处理领域不可或缺的工具。掌握 awk
意味着你能够以编程的方式处理和分析文本数据。
高级正则表达式与匹配:
- 正则表达式的完整支持:
awk
内置完整的 POSIX ERE (Extended Regular Expressions) 支持。你可以直接在模式中使用|
(或),+
(一个或多个),?
(零个或一个),()
(分组) 等,无需像grep
的 BRE 那样转义。 - 匹配操作符
~
和!~
: 用于判断字段或整个行是否匹配某个正则表达式。$1 ~ /pattern/ { print }
(如果第一个字段匹配模式则打印)$0 !~ /pattern/ { print }
(如果整行不匹配模式则打印)
match()
函数: 返回匹配字符串的起始位置和长度,并设置RSTART
和RLENGTH
变量,用于更精细的模式定位。sub()
和gsub()
函数: 用于替换字符串。sub(/regex/, "replacement", $0)
: 替换当前行中第一个匹配项。gsub(/regex/, "replacement", $0)
: 全局替换当前行中所有匹配项。可以在第三个参数指定要替换的字符串,否则默认为$0
。
- 正则表达式的完整支持:
流程控制语句:
- 条件语句:
if (condition) { action } else { action }
,支持else if
。 - 循环语句:
for (i=1; i<=NF; i++) { print $i }
(遍历字段)for (key in array) { print key, array[key] }
(遍历关联数组)while (condition) { action }
do { action } while (condition)
- 控制流命令:
break
,continue
,next
,exit
。next
: 跳过当前行,直接处理下一行输入。exit
: 立即退出awk
程序。
- 条件语句:
数组(关联数组/哈希表):
awk
的数组是关联数组(也叫哈希表或字典),可以使用数字或字符串作为索引。这是其统计和聚合功能的基石。- 示例:
awk '{count[$1]++} END {for (name in count) print name, count[name]}' access.log
(统计$1
列的出现次数) - 多维数组: 可以模拟多维数组,例如
array[index1, index2]
。
内置函数:
awk
提供了丰富的内置函数来处理字符串、数学运算、时间等。- 字符串函数:
length()
,substr()
,index()
,split()
,tolower()
,toupper()
,sprintf()
等。 - 数学函数:
int()
,sqrt()
,log()
,sin()
,cos()
,rand()
,srand()
等。 - 时间函数:
systime()
,strftime()
(格式化时间戳)。
- 字符串函数:
用户定义函数:
你可以像传统编程语言一样,在
awk
中定义自己的函数,提高代码复用性。示例:
Awk
1
2
3
4function square(x) {
return x * x
}
{ print square($1) }
记录和字段分隔符的精细控制:
RS
(Record Separator): 定义输入记录的分隔符(默认是换行符\n
)。ORS
(Output Record Separator): 定义输出记录的分隔符(默认是换行符\n
)。FS
(Field Separator): 定义输入字段的分隔符(默认是空格或制表符)。OFS
(Output Field Separator): 定义输出字段之间的分隔符(默认是空格)。- 示例:
awk -F':' -v OFS='\t' '{print $1, $NF}' /etc/passwd
(输入以:
分隔,输出以\t
分隔)
外部变量和命令行参数:
- 可以通过
-v var=value
选项向awk
脚本传递外部变量。 - 可以访问命令行参数
ARGV
数组和ARGC
变量。
- 可以通过
多文件处理:
awk
可以处理多个输入文件,并且你可以通过检查FILENAME
内置变量来识别当前处理的文件。