1、查看文件内容
1.1、cat(显示整个文件内容)
cat [选项] 文件名
常用选项:
-n
显示行号。-b
显示非空行的行号。-A
显示特殊字符。-s
压缩连续的空行为一行。-T
将制表符显示为^I
。-E
在每行末尾显示$
。
1.2、less(分页查看文件内容(支持上下滚动))
less [选项] 文件名
常用选项:
-N
显示行号。-i
忽略搜索时的大小写。-F
如果文件内容可以在一屏内显示,则直接显示并退出。-S
不换行显示长行(超出屏幕部分会被截断)。-X
退出 less 时不清除屏幕内容。+行号
从指定行号开始显示文件内容。+/模式
从匹配指定模式的第一行开始显示文件内容。
1.3、more(分页查看文件内容(仅支持向下滚动))
more [选项] 文件名
常用选项:
-d
显示提示信息(如按 h 显示帮助)。-f
强制显示长行(不换行)。-p
不滚屏,而是清屏后显示下一页。-c
不滚屏,而是从上到下刷新显示下一页。-s
将连续的空行压缩为一行。+行号
从指定行号开始显示文件内容。
1.4、head(显示文件的前几行(默认 10 行))
head [选项] 文件名
常用选项:
-n <行数>
显示文件的前 N 行(默认是 10 行)。-c <字节数>
显示文件的前 N 个字节。-q
不显示文件名(默认显示)。-v
总是显示文件名。
1.5、tail(显示文件的后几行(默认 10 行))
tail [选项] 文件名
常用选项:
-n <行数>
显示文件的最后 N 行(默认是 10 行)。-c <字节数>
显示文件的最后 N 个字节。-f
实时跟踪文件的新增内容(常用于监控日志文件)。-q
不显示文件名(默认显示)。-v
总是显示文件名。--pid=<进程ID>
与-f
一起使用,当指定进程结束时停止跟踪。
1.6、tac(从最后一行开始显示文件内容)
tac [选项] 文件名
常用选项:
-b
在行尾而不是行首分隔内容。-r
将分隔符视为正则表达式。-s <分隔符>
指定自定义的分隔符(默认是换行符)。
2、文本搜索
2.1、grep(搜索包含指定模式的行)
grep 是 Linux 中用于 搜索文本 的强大工具,可以在文件或输入中查找包含指定模式的行。grep 支持正则表达式,功能非常灵活。
grep [选项] 模式 [文件名]
常用选项:
-i
忽略大小写。-v
反向匹配,显示不包含模式的行。-n
显示匹配行的行号。-c
统计匹配行的数量。-r
或-R
递归搜索目录中的文件。-l
仅显示包含匹配模式的文件名。-L
仅显示不包含匹配模式的文件名。-w
匹配整个单词。-A <行数>
显示匹配行及其后的 N 行。-B <行数>
显示匹配行及其前的 N 行。-C <行数>
显示匹配行及其前后的 N 行。-E
使用扩展正则表达式(等同于 egrep)。-F
将模式视为固定字符串(等同于 fgrep)。--color
高亮显示匹配的文本。
使用示例:
在文件中搜索模式
grep "pattern" file.txt
忽略大小写搜索
grep -i "pattern" file.txt
显示匹配行的行号
grep -n "pattern" file.txt
统计匹配行的数量
grep -c "pattern" file.txt
递归搜索目录中的文件
grep -r "pattern" /path/to/dir
仅显示包含匹配模式的文件名
grep -l "pattern" /path/to/dir/*
匹配整个单词
grep -w "word" file.txt
显示匹配行及其后的 2 行
grep -A 2 "pattern" file.txt
使用扩展正则表达式
grep -E "pattern1|pattern2" file.txt
高亮显示匹配的文本
grep --color "pattern" file.txt
实际应用场景:
搜索日志文件中的错误信息
grep "error" /var/log/syslog
查找包含特定单词的文件
grep -l "keyword" /path/to/dir/*
查找不包含特定模式的文件
grep -L "pattern" /path/to/dir/*
统计文件中匹配模式的行数
grep -c "pattern" file.txt
递归搜索并显示匹配行及其上下文
grep -r -C 2 "pattern" /path/to/dir
注意事项:
- grep 默认区分大小写,使用 -i 选项可以忽略大小写。
- 如果模式中包含特殊字符,需要用引号括起来。
- 使用 -r 选项时,grep 会递归搜索指定目录及其子目录中的文件。
2.2、egrep(支持扩展正则表达式的 grep)
egrep [选项] 模式 [文件名]
常用选项:
-i
忽略大小写。-v
反向匹配,显示不包含模式的行。-n
显示匹配行的行号。-c
统计匹配行的数量。-r
或-R
递归搜索目录中的文件。-l
仅显示包含匹配模式的文件名。-L
仅显示不包含匹配模式的文件名。-w
匹配整个单词。-A <行数>
显示匹配行及其后的 N 行。-B <行数>
显示匹配行及其前的 N 行。-C <行数>
显示匹配行及其前后的 N 行。--color
高亮显示匹配的文本。
扩展正则表达式语法:
egrep 支持以下扩展正则表达式语法:
+
匹配前面的字符至少一次。?
匹配前面的字符零次或一次。- `
()
分组,用于组合多个模式。{}
指定匹配次数(例如 a{2} 匹配 aa)。
使用示例:
在文件中搜索模式
egrep "pattern" file.txt
忽略大小写搜索
egrep -i "pattern" file.txt
显示匹配行的行号
egrep -n "pattern" file.txt
统计匹配行的数量
egrep -c "pattern" file.txt
递归搜索目录中的文件
egrep -r "pattern" /path/to/dir
仅显示包含匹配模式的文件名
egrep -l "pattern" /path/to/dir/*
匹配多个模式之一
egrep "pattern1|pattern2" file.txt
匹配前面的字符至少一次
egrep "go+d" file.txt
#匹配 god、good、gooood 等。
匹配前面的字符零次或一次
egrep "colou?r" file.txt
#匹配 color 或 colour。
高亮显示匹配的文本
egrep --color "pattern" file.txt
实际应用场景:
搜索日志文件中的错误或警告
egrep "error|warning" /var/log/syslog
查找包含特定单词的文件
egrep -l "keyword" /path/to/dir/*
查找不包含特定模式的文件
egrep -L "pattern" /path/to/dir/*
统计文件中匹配模式的行数
egrep -c "pattern" file.txt
递归搜索并显示匹配行及其上下文
egrep -r -C 2 "pattern" /path/to/dir
2.3、fgrep(将模式视为固定字符串的 grep)
fgrep(Fixed-string GREP)是 grep 的一个变种,用于快速搜索固定字符串(不支持正则表达式)。它等同于 grep -F,适合在大型文件中快速查找纯文本内容。
fgrep [选项] "固定字符串" [文件名]
# 或(完全等效)
grep -F [选项] "固定字符串" [文件名]
核心特点:
- 只匹配字面文本:不解析正则表达式(如 .* ^$ 会被当作普通字符)。
- 速度更快:适合在大文件中搜索纯文本。
- 特殊字符安全:自动转义正则元字符(如 [ ] * ?)。
常用选项:
-i
忽略大小写-v
反向匹配(显示不包含的行)-n
显示行号-c
统计匹配行数-r
递归搜索目录-l
只显示包含匹配项的文件名-w
匹配完整单词(需用空格/标点分隔)
使用示例:
基本搜索
fgrep "hello" file.txt
# 等效于
grep -F "hello" file.txt
忽略大小写
fgrep -i "error" log.txt # 匹配 Error/ERROR/error
显示行号和文件名
fgrep -n "TODO" *.py # 输出格式:文件名:行号:匹配行
统计匹配次数
fgrep -c "404" access.log # 返回出现次数
递归搜索目录
fgrep -r "password" /etc/ # 搜索/etc下所有文件
匹配完整单词
fgrep -w "git" README.md # 匹配git但不匹配github
反向匹配(排除行)
fgrep -v "debug" app.log # 显示不包含debug的行
从标准输入搜索
cat data.csv | fgrep "2023"
典型应用场景:
快速搜索配置文件
fgrep "Port" /etc/ssh/sshd_config # 查找SSH端口配置
分析日志
fgrep -c "500" /var/log/nginx/error.log # 统计500错误次数
批量搜索代码
fgrep -rn "deprecated" src/ # 递归检查过时代码
安全扫描
fgrep -rl "password=" /var/www/ # 查找明文密码配置
注意事项:
- 性能优先:在GB级日志中搜索固定字符串时,fgrep 比 grep 快约30%。
- 复杂匹配:如需正则表达式,请换用 grep -E 或 egrep。
- 二进制文件:默认会输出二进制匹配(可用 -a 强制按文本处理)。
进阶使用:
多字符串搜索
fgrep -e "error" -e "warning" log.txt
高亮显示结果
fgrep --color=auto "FATAL" system.log
结合find使用
find /var/log -type f -exec fgrep -l "segfault" {} +
#通过 fgrep 可以高效完成纯文本搜索任务,尤其在处理特殊字符或大文件时优势明显。如需更复杂的模式匹配,再考虑使用 grep 或 egrep。
2.4、ack(专为代码搜索设计的工具)
ack 是一个用于在文件中搜索文本的命令行工具,类似于 grep,但专为程序员设计,默认会忽略版本控制目录和备份文件。
ack [选项] 模式 [文件/目录]
#模式:要搜索的文本或正则表达式。
#文件/目录:指定要搜索的文件或目录(可选,默认是当前目录及其子目录)。
常用选项:
搜索选项:
# -i:忽略大小写。
ack -i "hello"
# -w:匹配整个单词。
ack -w "hello"
# 反向搜索,显示不匹配的行。
ack -v "hello"
# -Q:将模式视为普通字符串(禁用正则表达式)。
ack -Q "hello.world"
输出控制:
# -l:只显示包含匹配项的文件名。
ack -l "hello"
# -c:显示每个文件的匹配次数。
ack -c "hello"
# -h:不显示文件名(只显示匹配的行)。
ack -h "hello"
# -H:总是显示文件名(默认行为)。
ack -H "hello"
# --color:高亮显示匹配项。
ack --color "hello"
文件类型:
# --python:只搜索 Python 文件。
ack --python "import"
# --html:只搜索 HTML 文件。
ack --html "title"
# --type-add:添加自定义文件类型。
ack --type-add=mytype:ext:myext "pattern"
# --type-set:定义新的文件类型。
ack --type-set=mytype:ext:myext "pattern"
目录控制:
# -r:递归搜索子目录(默认行为)。
ack -r "hello"
# --ignore-dir:忽略指定目录。
ack --ignore-dir=tmp "hello"
# --no-ignore-dir:不忽略任何目录。
ack --no-ignore-dir "hello"
上下文:
# -C NUM:显示匹配行的前后 NUM 行上下文。
ack -C 3 "hello"
# -B NUM:显示匹配行的前 NUM 行。
ack -B 2 "hello"
# -A NUM:显示匹配行的后 NUM 行。
ack -A 2 "hello"
高级用法:
正则表达式:
# ack 支持 Perl 兼容的正则表达式(PCRE),例如:
ack "\bword\b" # 匹配整个单词 "word"
ack "foo.*bar" # 匹配 "foo" 和 "bar" 之间的任意字符
组合选项:
# 可以将多个选项组合使用,例如:
ack -i -l --python "import"
# 这会在所有 Python 文件中搜索 import(忽略大小写),并只显示文件名。
自定义文件类型:
# 可以通过 --type-add 或 --type-set 定义自定义文件类型:
ack --type-add=mytype:ext:myext "pattern"
#然后使用:
ack --mytype "pattern"
示例:
#搜索所有文件中包含 hello 的行
ack "hello"
#搜索所有 Python 文件中包含 import 的行
ack --python "import"
#忽略 node_modules 目录,搜索所有文件中包含 function 的行
ack --ignore-dir=node_modules "function"
#显示所有包含 error 的文件名
ack -l "error"
#高亮显示匹配项
ack --color "hello"
#搜索并显示上下文
ack -C 2 "hello"
帮助信息:
#查看 ack 的帮助信息:
ack --help
#查看支持的文件类型:
ack --help-types
2.5、ag(更快的代码搜索工具)
ag(The Silver Searcher)是一个比 ack 更快的代码搜索工具,专为程序员优化。它类似于 ack 和 grep,但速度更快,并且默认忽略 .gitignore 中的文件。
ag [选项] 模式 [路径]
# 模式:要搜索的字符串或正则表达式。
# 路径:要搜索的目录或文件(可选,默认当前目录)。
常用选项:
搜索控制:
选项 | 说明 | 示例 |
---|---|---|
-i | 忽略大小写 | ag -i "hello" |
-w | 匹配整个单词 | ag -w "main" |
-v | 反向匹配(排除) | ag -v "TODO" |
-Q | 禁用正则(字面匹配) | ag -Q "foo.bar" |
-G <pattern> | 只搜索匹配的文件名 | ag -G "\.py$" "import" |
输出控制:
选项 | 说明 | 示例 |
---|---|---|
-l | 只显示文件名 | ag -l "error" |
-c | 显示匹配数量 | ag -c "TODO" |
--color | 高亮匹配(默认开启) | ag --color "warning" |
--nocolor | 禁用高亮 | ag --nocolor "error" |
-A <n> | 显示匹配行后的 n 行 | ag -A 2 "exception" |
-B <n> | 显示匹配行前的 n 行 | ag -B 2 "if" |
-C <n> | 显示匹配行前后的 n 行 | ag -C 3 "function" |
文件类型:
选项 | 说明 | 示例 |
---|---|---|
--python | 只搜索 Python 文件 | ag --python "import" |
--cpp | 只搜索 C++ 文件 | ag --cpp "class" |
--js | 只搜索 JavaScript 文件 | ag --js "function" |
--html | 只搜索 HTML 文件 | ag --html "div" |
--ignore <pattern> | 忽略匹配的文件 | ag --ignore "*.min.js" "function" |
目录控制:
选项 | 说明 | 示例 |
---|---|---|
--hidden | 搜索隐藏文件 | ag --hidden "secret" |
--skip-vcs-ignores | 忽略 .gitignore | ag --skip-vcs-ignores "temp" |
-U | 搜索二进制文件 | ag -U "\x00" |
高级用法:
#正则表达式
ag "foo.*bar" # 匹配 "foo" 后跟任意字符和 "bar"
ag "\bclass\b" # 精确匹配单词 "class"
#组合选项
ag -i -G "\.py$" "import" # 在 Python 文件中搜索 "import"(忽略大小写)
ag -l --js "function" # 列出所有包含 "function" 的 JS 文件
#搜索特定文件
ag "pattern" /path/to/file
#排除目录
ag --ignore-dir=node_modules "function"
示例:
#搜索所有文件中包含 error 的行
ag "error"
#搜索 Python 文件中的 import
ag --python "import"
#忽略 node_modules 并搜索 function
ag --ignore-dir=node_modules "function"
#显示匹配行的上下文
ag -C 2 "exception"
#只显示文件名
ag -l "TODO"
3、文本过滤
3.1、awk(大的文本处理工具,支持按列处理)
awk 是 Linux 中一个强大的 文本处理工具,擅长对 结构化文本(如日志、CSV、配置文件等)进行 提取、计算、格式化输出。它不仅是命令行工具,还是一种 脚本语言,支持变量、条件判断、循环等编程特性。
基本语法:
awk '模式 {动作}' 文件名
# 模式:可选,用于筛选行(如 /regex/, NR==1, $1 > 10)。
# 动作:对匹配的行执行的操作(如 print, printf, 计算等)。
# 文件名:要处理的文件(若不指定,则从标准输入读取)。
核心概念:
字段分隔:
- 默认以
空格/Tab
分割每行,字段依次记为$1
,$2
, …,$NF
。 $0
表示整行,NF
是字段总数,NR
是当前行号。
内置变量:
变量 | 说明 | 示例 |
---|---|---|
FS | 输入字段分隔符(默认空格) | awk -F':' '{print $1}' |
OFS | 输出字段分隔符(默认空格) | awk 'BEGIN{OFS="-"}{print $1,$2}' |
RS | 输入行分隔符(默认换行) | awk 'BEGIN{RS=";"}{print}' |
ORS | 输出行分隔符(默认换行) | awk 'BEGIN{ORS=" "}{print}' |
FILENAME | 当前文件名 | awk '{print FILENAME}' |
常用操作:
#打印字段
# 打印第1列和第3列
awk '{print $1, $3}' file.txt
# 打印行号和整行内容
awk '{print NR, $0}' file.txt
# 条件筛选
# 打印第2列大于100的行
awk '$2 > 100 {print $0}' file.txt
# 匹配包含 "error" 的行
awk '/error/ {print}' file.txt
# 第1列等于 "root" 的行
awk '$1 == "root" {print}' /etc/passwd
#计算统计
# 计算第3列的总和
awk '{sum += $3} END {print sum}' file.txt
# 统计行数
awk 'END {print NR}' file.txt
# 计算列平均值
awk '{sum += $1} END {print sum/NR}' file.txt
# 格式化输出
# 类似C语言的printf
awk '{printf "Name: %-10s Age: %d\n", $1, $2}' data.txt
高级用法:
BEGIN和END块:
- BEGIN:在处理文件前执行(如初始化变量)。
- END:在处理完所有行后执行(如输出统计结果)。
# 计算文件的行数、单词数、字符数(类似wc)
awk 'BEGIN{lines=0; words=0; chars=0} {lines++; words+=NF; chars+=length($0)} END{print lines, words, chars}' file.txt
数组与去重:
# 统计第1列出现的次数
awk '{count[$1]++} END {for (word in count) print word, count[word]}' file.txt
# 去重(按第1列)
awk '!seen[$1]++' file.txt
自定义函数:
# 定义函数计算平方
awk 'function square(x) {return x*x} {print square($1)}' numbers.txt
多文件处理:
# 处理多个文件,并标注文件名
awk '{print FILENAME, $0}' file1.txt file2.txt
经典案例:
#提取日志中的IP地址
awk '{print $1}' access.log | sort | uniq -c | sort -nr
#分析CSV文件
awk -F',' '{print $2, $3}' data.csv
#生成报告
awk 'BEGIN{print "Name\tScore"} $2 > 80 {print $1, $2}' scores.txt
#修改分隔符
# 以冒号分隔(如/etc/passwd)
awk -F':' '{print $1, $6}' /etc/passwd
性能优化:
#避免多次读取文件:用数组存储中间结果。
#使用 next 跳过不相关的行:
awk '/error/ {print; next} {count++} END {print count}' log.txt
总结:
- 简单字段提取
awk '{print $1}'
- 条件过滤
awk '$2 > 100'
- 统计计算
awk '{sum+=$1} END{print sum}'
- 文本格式化
awk '{printf "%-10s %d\n", $1, $2}'
- 复杂数据处理
使用 BEGIN/END 和数组
3.2、sed(流编辑器,用于文本替换、删除等操作)
sed(Stream Editor,流编辑器)是 Linux 中强大的 文本处理工具,主要用于 查找、替换、删除、插入 文本内容,支持 正则表达式,适合批量处理文件或数据流。
# 命令格式
sed [选项] '命令' 文件名
# 选项:控制 sed 的行为(如 -i 直接修改文件)。
# 命令:指定对文本执行的操作(如替换 s/old/new/)。
# 文件名:要处理的文件(若不指定,则从标准输入读取)。
# 脚本格式
sed [选项] -f 命令脚本 文件名
3.2.1、常用选项
选项 | 说明 | 示例 |
---|---|---|
-e 或--expression | 执行多个命令,直接在命令行模式上进行sed动作编辑,此为默认选项 | sed -e 's/foo/bar/' -e 's/hello/world/' file.txt |
-f 或--file | 将sed的动作写在i个文件内,用-f filename 执行filename内的sed动作 | sed -f script.sed file.txt |
-i 或--inplace | 直接修改文件内容 | sed -i 's/foo/bar/' file.txt |
-r 或-E | 支持扩展表达式 | sed -r 's/[0-9]+/NUM/' file.txt |
-n 或--quiet 或--silent | 仅显示处理后的行(默认打印所有行) | sed -n '1,5p' file.txt |
--degug | 以注解的方式显示sed的执行过程,帮助调试脚本 | sed --debug 's/foo/bar/' filename |
--follow-symlinks | 当指定-i时,sed会跟随符号链接指向的实际文件进行编辑 | sed -i --follow-symlinks 's/foo/bar/' symlink.txt |
-s 或--separate | 将多个输入文件视为独立的流,而不是作为一个连续的流处理 | sed -s 's/foo/bar/' file1.txt file2.txt |
--sandbox | 以沙盒模式运行,禁止使用e,r,w命令,防止sed修改文件或执行外部命令 | sed --sandbox 's/foo/bar/' filename |
-u 或--unbuffered | 减少从输入文件读取数据时的缓冲区大小,并更频繁地刷新输出 | sed -u 's/foo/bar/' filename |
-z 或--null-date | 将输入中的行分隔符从换行符\n改为NUL字符\0,这在处理二进制数据或以NUL作为分隔符的文本时很有用 | sed -z 's/foo/bar/' filename |
-h 或--help | 显示帮助 | |
-V 或--version | 显示版本信息 |
3.2.2、匹配条件
格式 | 描述 |
---|---|
/regexp/ | 使用正则表达式,匹配数据行 |
n(数字) | 使用 行号 匹配,范围是 1-$ |
addr1, addr2 | 使用 行号或正则 定位,匹配从addr1到addr2的所有行 |
add1,+n | 使用 行号或正则 定位,匹配从addr1开始及以后的n行 |
n~step | 使用 行号,匹配从行号n开始,步长为step的所有数据行 |
3.2.3、定界符
/
在sed中未做定界符使用,也可以使用任意的定界符
sed 's|foo|bar|g' filename
sed 's:foo:bar:g' filename
# 定界符出现在样式内部时,需要进行转义
sed 's/\/bin/\/usr/bin/g' filename
3.2.4、操作指令
指令 | 描述 | 例子 |
---|---|---|
! | 表示后面的命令,对"所有没有被选定"的行发生作用 | sed -n '/foo/!p' filename 只打印不含有foo的行 |
p | 打印当前匹配的数据行(常配合-n使用) | sed -n '/foo/p' filename 只打印含有foo的行 |
l | 小写L,打印当前匹配的数据行,并显示控制字符,如回车符\,结束符$等 | sed -n '/foo/l' filename 只打印含有foo的行,并显示控制字符 |
= | 打印当前读取的数据所在的"行数" | sed -n '$=' filename 打印文件最后一行的行数 |
a\ | 在匹配的数据行"后"插入文本内容 | sed '/foo/a\hello' filename 在每个含有foo行,下面追加一行hello |
i\ | 在匹配的数据行"前"插入文本内容 | sed '/foo/i\world' filename 在每个含有foo行,上面插入一行world |
c\ | 将匹配的数据行""整行"内容修改为指定的文本内容 | sed '/foo/c\good book' filename 将每个含有foo的整行替换为good book |
d | 行删除,删除匹配的数据行整行内容 | sed '/foo/d' filename 删除每个含有foo的行 |
r | 从文件中读取数据,并追加到匹配的数据行后面 | sed -i '/foo/r datefile' filename 将文件datefile的内容,追加在文件filename中每个含有foo的行下面 |
w | 将当前匹配到的数据,写入指定的文件中 | sed -n '/foo/w newfile' filename 将文件filename中每个含有foo的行,写入到新文件newfile里面 |
q | 立刻退出sed脚本 | sed '5q' filename 打印第5行前的数据,类似sed -n '1,5p' |
s/regexp/replace/ | 使用正则匹配,将匹配的数据替换为指定的内容 | sed 's/foo/bar/' filename 将每个含有foo行中第一次出现的foo,替换为bar |
n (数字) | 只替换第n次出现的匹配项 | sed 's/foo/bar/2' filename 将每个含有foo行中,第2次出现的foo替换为bar |
g | 全局替换,替换每一行中的所有匹配项 | sed 's/foo/bar/g' filename filename 将每行中的foo,替换为bar |
i | 忽略大小写,进行不分区大小写的匹配 | sed 'foo/i' filename 打印含有foo或FOO的行 |
e | 执行,允许在替换文本中进行命令执行 | echo "ls /tmp" | sed 's/ls/ls -l/e' 将sed命令的结果,当作命令执行:即输出ls -l /tmp 命令的结果 |
& | 引用匹配的整个字符串 | echo "hello" | sed 's/hello/& XXX/' 结果为hello XXX |
3.2.5、模式空间和保留空间
sed 的保留空间(Hold Space)是 sed 处理文本时的一个辅助缓冲区,与模式空间(Pattern Space)配合使用可以实现更复杂的文本处理操作。
- 模式空间(Pattern Space): 存放当前处理的行,是 sed 主要的工作区域
- 保留空间(Hold Space): 辅助缓冲区,用于临时存储内容
操作保留空间的命令:
h
将模式空间内容复制到保留空间(覆盖保留空间原有内容)H
将模式空间内容追加到保留空间(保留原有内容,添加新行)g
将保留空间内容复制到模式空间(覆盖模式空间原有内容)G
将保留空间内容追加到模式空间(保留原有内容,添加新行)n
读取下一行数据复制到模式空间(覆盖模式空间原有内容)N
读取下一行数据追加到模式空间(保留原有内容,添加新行)x
交换模式空间和保留空间的内容P
大写P,仅打印多行模式空间第一行D
大写D,仅删除多行模式空间第一行
使用示例:
简单复制和交换:
# 复制第一行到保留空间并在最后一行后输出
sed -n '1h;$G;p' file.txt
# 交换第一行和最后一行
sed -n '1h;${x;G};p' file.txt
反转文件内容:
sed '1!G;h;$!d' file.txt
# 1!G - 不是第一行时,将保留空间追加到模式空间
# h - 将模式空间复制到保留空间
# $!d - 不是最后一行时删除模式空间内容
删除连续重复行:
sed '$!N; /^\(.*\)\n\1$/!P; D' file.txt
# N:读入下一行。
# P:如果两行不重复,打印第一行。
# D:删除第一行,继续处理剩余部分。
合并相邻行:
sed ':a;N;s/\n/ /;ba' file.txt
# 循环读取行(N),替换换行符为空格。
合并特定行:
# 将奇数行和偶数行合并
sed -n 'N;s/\n/ /;p' file.txt
条件性使用保留空间:
# 如果行包含"pattern",则与保留空间内容合并
sed '/pattern/{h;d;}; G; s/\n/ /' file.txt
3.2.6、条件分支
sed 的条件分支功能允许根据特定条件执行不同的编辑命令,这是 sed 编程中非常强大的功能。
基本分支命令:
标签定义与跳转:
:label
- 定义标签(label 可以是任意名称)b label
- 无条件跳转到指定标签t label
- 条件跳转(如果自上次读取行以来有成功替换,则跳转)T label
- 条件跳转(如果自上次读取行以来没有成功替换,则跳转)
条件执行:command1; command2
- 顺序执行多个命令command1 && command2
- 只有 command1 成功才执行 command2command1 || command2
- 只有 command1 失败才执行 command2
分支控制示例:
简单条件替换:
# 如果行包含"start",则删除直到"end"的所有行
sed '/start/,/end/d' file.txt
复杂分支逻辑:
# 如果行匹配"pattern1",则执行一组命令,否则执行另一组
sed '/pattern1/ {
s/a/A/g
s/b/B/g
b end # 跳过else部分
}
{
s/a/X/g
s/b/Y/g
}
:end' file.txt
循环处理:
# 删除所有空行(使用循环)
sed ':top
/^$/ {
N # 读取下一行
s/\n// # 删除换行符
b top # 返回检查
}' file.txt
条件跳转(t命令):
# 只在替换成功时执行后续命令
sed 's/foo/bar/; t; s/other/replace/' file.txt
多条件处理:
sed '{
/pattern1/ b case1
/pattern2/ b case2
b default # 默认情况
:case1
s/a/A/
b end
:case2
s/b/B/
b end
:default
s/.*/DEFAULT/
:end
}' file.txt
状态机实现:
# 简单的状态机示例
sed '{
/^begin$/ {
s//processing/
b state1
}
:state1
/^data/ {
s//processed/
b state1
}
/^end$/ {
s//finished/
b
}
}' file.txt
复杂文本转换:
# 将多行记录转换为单行
sed '/^Record:/ {
:loop
N
/^\nRecord:/! {
s/\n/ /g
b loop
}
P
D
}' data.txt
注意事项:
- 标签名称不能包含空格或特殊字符
- 分支命令会改变 sed 的正常执行流程
- 复杂的分支逻辑可能难以调试,建议先在小样本上测试
- 某些 sed 版本(如BSD/macOS sed)对标签和分支的实现可能略有不同
3.2.7、匹配范围示例
#行号范围:打印第3行到第5行
sed -n '3,5p' filename
#正则表达式匹配范围:从匹配start_pattern的行开始,到匹配end_pattern的行结束
sed -n '/start_pattern/,/end_pattern/p' filename
#命令组合:从第1行开始,到第一个空白行为止
sed -n '1,/^$/p' filename
#倒数行范围:从第1行开始,直到匹配end_pattern的行之前(使用!进行取反)
sed -n '1,/end_pattern/!p' filename
#指定行的倍数:打印所有奇数行(从第一行开始,步长为 2)
sed -n '1~2p' filename
3.2.8、增删改示例
基础替换:
#只替换文本中第一次出现的匹配项,并将结果输出到标准输出
sed 's/foo/bar/' filename
#只替换每行中第三次出现的匹配项
sed 's/foo/bar/3' filename
#只打印替换过的行
sed -n 's/foo/bar/p' filename
#编辑原文件,同时创建 filename.bak 备份
sed -i.bak 's/foo/bar/' filename
#忽略大小写进行替换
sed 's/foo/bar/i' filename
#全局替换
sed 's/foo/bar/g' filename
#全局替换,每行替换从第 2 次开始出现的匹配项
sed 's/foo/bar/2g' filename
组合替换:
#替换并写入新文件:将替换过的行写入 output.txt
sed 's/foo/bar/w output.txt' filename
#结合标记符:在匹配的字符串后添加后缀
sed 's/foo/&.bak/' filename
#执行sed结果的命令(谨慎使用,可能导致安全风险)
sed 's/systemctl start/systemctl status/e' filename
echo "ls /tmp" | sed 's/ls/ls -l/e'
#行号范围:将第3行到第5行中的"foo"替换为"bar"
sed '3,5s/foo/bar/g' filename
#正则表达式匹配范围:从包含"start"的行开始,到包含"end"的行结束,替换"foo"为"bar"
sed '/start/,/end/s/foo/bar/g' filename
#命令组合:从第1行开始,到第一个空白行为止,替换"foo"为"bar"
sed '1,/^$/s/foo/bar/g' filename
#倒数行范围:从第1行开始,直到包含"end"的行之前,替换"foo"为"bar"
sed '1,/end/!s/foo/bar/g' filename
#指定行的倍数:替换所有奇数行中的"foo"为"bar"
sed '1~2s/foo/bar/g' filename
行下追加(a\):
#将 "this is a test line" 追加到含有 "hello" 行的下面
sed -i '/hello/a\this is a test line' filename
#在第 2 行之后插入 "this is a test line"
sed -i '2a\this is a test line' filename
行上插入(i\):
#将 "this is a test line" 插入到含有 "librarookie" 的行上面
sed -i '/librarookie/i\this is a test line' filename
#在第 5 行之前插入 "this is a test line"
sed -i '5i\this is a test line' filename
替换当前行(c\):
#将含有 "librarookie" 的行变成 "this is a test line"
sed -i '/librarookie/c\this is a test line' filename
#将第 5 行变成 "this is a test line"
sed -i '5c\this is a test line' filename
删除操作(d):
#删除全文
sed -i 'd' filename
#删除第 2 行
sed -i '2d' filename
#删除最后一行
sed -i '$d' filename
#删除空白行
sed -i '/^$/d' filename
#以 # 号开头的行(删除注释)
sed -i '/^#/d' filename
#删除文件中所有开头是 test的行
sed -i '/^test/d' filename
#删除文件的第 2 行到 末尾所有行
sed -i '2,$d' filename
3.2.9、脚本文件(-f)
sed脚本是一个sed的命令清单,启动sed时,以-f指定脚本文件名。Sed脚本规则如下:
- 在命令的末尾不能有任何空白或文本
- 如果在一行中有多个命令,要用分号分隔
- 以#开头的行为注释行,且不能跨行
#这将按照 scriptfile.sed 文件中的命令来编辑 filename 文件
sed -f scriptfile.sed filename
#如果你不希望实际修改文件,可以添加 -n 标志和 p命令来打印结果而不是直接写入文件
sed -nf scriptfile.sed filename
scriptfile.sed内容如下:
# 这是注释,会被sed忽略
# 替换文件中的第一行中的"old_string"为"new_string"
1s/old_string/new_string/
# 从第3行到第5行,替换"foo"为"bar"
3,5s/foo/bar/g
# 删除包含"delete_this_line"的行
/delete_this_line/d
# 在包含"insert_before"的行之前插入新行
/insert_before/i\
This is the new line to insert
# 在文件末尾添加一行
$ a\
This is the new line at the end of the file
3.2.10、标记操作
已匹配字符串标记($):
#正则表达式 "\w\+" 匹配每一个单词,使用 [&] 替换它,& 对应于之前所匹配到的单词:
echo this is a test line | sed 's/\w\+/[&]/g'
[this] [is] [a] [test] [line]
# 将 hello 替换为 helloworld
sed 's/hello/&world/' filename
helloworld
子串匹配标记(\1):
\(..\)
用于匹配子串,对于匹配到的第一个子串标记为\1
,依次类推- 未定义
\(..\)
时,效果等同于&
标记
#echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
this is 7 in a number
#命令中 digit 7,被替换成了 7。样式匹配到的子串是 7。
#\(..\) 用于匹配子串。[a-z]+ 匹配小写字母,为第一个子串\1;[A-Z]+ 匹配大写字母,为第二个子串\2
echo "world HELLO" | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
HELLO world
# HELLO 被标记为 \1,将
echo "hello world" | sed 's/\(hello\) world/\1 librarookie/'
hello librarookie
3.2.11、组合多个表达式(-e)
#1. 使用 -e 选项,指定多个 sed 表达式
sed -e '表达式' -e '表达式' filename
#2. 使用管道符 | ,对结果重复使用 sed 命令
sed '表达式' | sed '表达式' filename
#1. 在表达式中使用 ;
sed '表达式; 表达式' filename
3.2.12、文件读写(r/w)
#1. 从文件读取(r)
#将文件 datafile 里的内容读取出来,显示在文件 filename 中匹配 test 的行下面
#如果匹配多行,则将文件 datafile 的内容,显示在文件 filename 中所有匹配 test 的行下面
sed -i '/test/r datafile' filename
#2. 写入新文件(w)
#将文件 filename 中所有匹配 test 的数据行,都写入新文件 newfile 里面
sed -n '/test/w newfile' filename
#将替换后的 filename 写入 newfile
sed 's/foo/bar/w newfile' filename
3.2.13、多行操作
保持和获取:
#将任何包含 test 的行都被复制并追加到该文件的末尾
sed -e '/test/h' -e '$G' file
# -e '/test/h'
#1. 匹配 test 的行被找到后,将存入模式空间,
#2. h 命令将其复制并存入保留空间(保持缓存区的特殊缓冲区内)。
#
# -e '$G'
#1. 当到达最后一行($)后,
#2. G 命令取出保留空间的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中的行的末尾。
#3. 在这个例子中就是追加到最后一行。
保持和互换:
sed -e '/test/h' -e '/check/x' file
打印奇数行或偶数行:
#方法1:利用 n ,打印一行,隐藏一行
sed -n 'p;n' test.txt #奇数行
sed -n 'n;p' test.txt #偶数行
#方法2:利用步长 2 ,跳过非目标行
sed -n '1~2p' test.txt #奇数行
sed -n '2~2p' test.txt #偶数行
3.2.13、经典案例
删除连续重复行
sed '$!N; /^$.*$\n\1$/!P; D' file.txt
提取 XML/HTML 标签内容
sed -n 's/<title>$.*$<\/title>/\1/p' file.html
替换 IPv4 地址
sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}/[REDACTED]/g' log.txt
格式化 CSV 文件
sed 's/,/ | /g' data.csv
删除空行:
sed '/^$/d' file.txt
# 作用:删除所有空行(^$ 匹配空行)。
# 变体:删除含空格/Tab 的空行:
sed '/^\s*$/d' file.txt
替换文件中的字符串(全局替换)
sed 's/old/new/g' file.txt
#作用:将所有 old 替换为 new。
#忽略大小写:
sed 's/old/new/gi' file.txt
删除注释行(以 # 或 // 开头)
sed '/^#/d' file.txt # 删除 # 开头的行
sed '/^\/\//d' file.txt # 删除 // 开头的行
删除行首/行尾空格
sed 's/^[ \t]*//' file.txt # 删除行首空格/Tab
sed 's/[ \t]*$//' file.txt # 删除行尾空格/Tab
#合并操作:
sed 's/^[ \t]*//;s/[ \t]*$//' file.txt
在指定行后插入内容
sed '/pattern/a\插入的内容' file.txt
#示例:在 server { 后插入一行配置:
sed '/server {/a\ listen 80;' nginx.conf
提取两个标记之间的内容
sed -n '/start/,/end/p' file.txt
#示例:提取 <!-- BEGIN --> 和 <!-- END --> 之间的内容:
sed -n '/<!-- BEGIN -->/,/<!-- END -->/p' file.html
反转文件的行序
sed '1!G;h;$!d' file.txt
#1!G:非第一行时,将保持空间(Hold Space)追加到模式空间。
#h:每次将模式空间复制到保持空间。
#$!d:非最后一行时删除模式空间(不打印)。
合并相邻两行
sed 'N;s/\n/ /' file.txt
#作用:将两行合并为一行(换行符替换为空格)。
#合并所有行:
sed ':a;N;$!ba;s/\n/ /g' file.txt
删除重复的相邻行
sed '$!N; /^$.*$\n\1$/!P; D' file.txt
#N:读取下一行。
#P:如果两行不同,打印第一行。
#D:删除第一行,继续处理剩余内容。
格式化日志(提取特定字段)
sed -n 's/.*$ERROR:[^ ]*$.*/\1/p' log.txt
#示例:从日志中提取 ERROR: 开头的消息:
sed -n 's/.*$ERROR:[^ ]*$.*/\1/p' app.log
替换 IP 地址为 [REDACTED]
sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}/[REDACTED]/g' file.txt
#扩展正则(-r):简化 () 和 {} 的转义。
将 CSV 文件转换为 Markdown 表格
sed 's/,/ | /g; 1i\| --- | --- |' data.csv
#作用:将逗号替换为 |,并在首行插入表头分隔线。
删除 HTML/XML 标签
sed 's/<[^>]*>//g' file.html
#注意:简单场景可用,复杂 HTML 建议用 awk 或专用工具。
在匹配行前/后添加行
sed '/pattern/i\插入的行' file.txt # 在匹配行前插入
sed '/pattern/a\追加的行' file.txt # 在匹配行后追加
仅打印匹配的行及其后 N 行
sed -n '/pattern/,+3p' file.txt # 打印匹配行及后 3 行
3.3、cut(按列提取文本)
cut 是 Linux 中一个简单高效的 文本列提取工具,专门用于按 字段(列)、字符位置 或 分隔符 切割文本。它适合处理结构化数据(如 CSV、日志、配置文件等),通常与 grep、sort 等命令结合使用。
cut [选项] [文件]
# 若不指定文件,则从标准输入(stdin)读取数据。
字段选择选项:
-f, --fields=LIST
:指定要提取的字段(列),支持范围、逗号分隔列表
N
:第N个字段N-
:从第N个字段到行尾N-M
:第N到第M个字段,
:多选(如 1,3)
# 提取第1列(Tab分隔)
cut -f1 file.txt
# 提取第1和3列(逗号分隔)
cut -d',' -f1,3 data.csv
# 提取第2列到行尾
cut -f2- log.txt
分隔符控制选项:
-d, --delimiter=DELIM
:指定字段分隔符(默认Tab),仅支持单字符分隔符(如: 、 ,
)。
# 以冒号分隔提取第1列(如/etc/passwd)
cut -d':' -f1 /etc/passwd
-s, --only-delimited
:忽略不包含分隔符的行(如注释行)
# 仅处理包含冒号的行
cut -d':' -s -f1 config.txt
字符位置选项:
-c, --characters=LIST
:按字符位置切割(适合固定宽度文本
N
:第N个字符N-M
:第N到第M个字符-M
:行首到第M个字符N-
:第N个字符到行尾
# 提取每行前5个字符
cut -c1-5 file.txt
# 提取第3、5、7个字符
cut -c3,5,7 data.txt
反选与补充选项:
--complement
:反选字段/字符(保留未指定的部分)。
# 排除第2列(保留其他所有列)
cut -d',' -f2 --complement data.csv
# 排除前10个字符
cut -c1-10 --complement log.txt
输出控制选项:
--output-delimiter=STRING
:指定输出时的分隔符(默认使用输入分隔符)。
# 用分号连接输出的列
cut -d',' -f1,3 --output-delimiter=';' data.csv
特殊场景选项:
-z, --zero-terminated
:以 \0(而非换行符)作为行分隔符,用于处理含换行符的文本。
# 处理含换行符的文件(如find -print0的输出)
find . -name "*.txt" -print0 | cut -z -d'/' -f3
常用操作:
按字段提取(适合分隔符明确的文本)
# 提取第1列(默认Tab分隔)
cut -f1 data.txt
# 提取第1和3列(逗号分隔)
cut -d',' -f1,3 file.csv
# 提取第2列之后的所有列
cut -d' ' -f2- log.txt
按字符位置提取(固定宽度文本)
# 提取每行的前5个字符
cut -c1-5 file.txt
# 提取第3到第10个字符
cut -c3-10 data.txt
# 提取第1、3、5个字符
cut -c1,3,5 letters.txt
排除指定字段
# 排除第2列(保留其他所有列)
cut -d',' -f2 --complement data.csv
处理无分隔符的行
# 忽略没有冒号的行(如过滤注释行)
cut -d':' -s -f1 /etc/passwd
高级用法:
集合其他命令:
# 提取日志中的IP地址(第1列)并统计
grep "GET" access.log | cut -d' ' -f1 | sort | uniq -c
# 提取CPU型号(/proc/cpuinfo)
grep "model name" /proc/cpuinfo | cut -d':' -f2
处理多字节字符(如UTF-8)
# 正确切割包含中文的文本(按字符而非字节)
echo "你好世界" | cut -c1-2 # 输出“你好”
自定义输出分隔符
# 用分号连接输出的列(需结合tr替换)
cut -d',' -f1,3 file.csv | tr ',' ';'
经典案例:
提取用户名(/etc/passwd)
cut -d':' -f1 /etc/passwd
分析CSV文件
# 提取第1列和第4列(逗号分隔)
cut -d',' -f1,4 data.csv
切割固定宽度日志
# 提取日志的时间戳(假设前15个字符是时间)
cut -c1-15 server.log
排除注释行
# 提取非注释的配置项(#开头为注释)
grep -v "^#" config.conf | cut -d'=' -f1
注意事项:
- 分隔符限制:cut 只支持单字符分隔符(如 -d’:‘),不能直接处理多字符分隔符(如 ||)。复杂场景建议用 awk -F’分隔符’。
- 字段顺序:-f2,1 不会交换列顺序,而是按原始顺序提取(输出仍为第2列后跟第1列)。
- 性能优化:处理大文件时,cut 比 awk 更轻量,但功能有限。
3.4、tr(字符替换或删除)
tr(translate)是 Linux 中一个简单高效的 字符替换/删除工具,主要用于对输入文本的字符进行 一对一替换、删除或压缩重复字符。它不支持正则表达式,但处理速度快,适合简单的字符级操作。
tr [选项] SET1 [SET2]
# 输入:通常通过管道(|)或重定向(<)传递。
# 功能:
# 将 SET1 中的字符替换为 SET2 中的对应字符。
# 若 SET2 未指定,则默认删除 SET1 中的字符。
常用选项:
-d
删除 SET1 中的字符-s
压缩 SET1 中的连续重复字符(保留一个)-c
对 SET1 的 补集 操作(即匹配不在 SET1 中的字符)-t
将 SET1 截断为与 SET2 等长(避免多字符替换错误)
特殊字符表示:
字符集合:
a-z
所有小写字母A-Z
所有大写字母0-9
所有数字[:alpha:]
所有字母(同 a-zA-Z)[:digit:]
所有数字(同 0-9)[:space:]
所有空白字符(空格、Tab等)
转义字符:
\n
换行符\t
制表符\r
回车符\\
反斜杠本身
经典案例:
字符替换
echo "hello" | tr 'a-z' 'A-Z' # 小写转大写 → HELLO
echo "HELLO" | tr 'A-Z' 'a-z' # 大写转小写 → hello
# 注:SET1 和 SET2 需等长(如 a-z 对应 A-Z)。
删除指定字符
echo "hello 123" | tr -d '0-9' # 删除数字 → hello
echo "file.txt" | tr -d '.txt' # 删除指定字符 → file
压缩重复字符
echo "heeellooo" | tr -s 'eo' # 压缩 e 和 o → helo
echo "aaabbbccc" | tr -s 'a-z' # 压缩所有连续字母 → abc
替换换行符为空格
cat file.txt | tr '\n' ' ' # 将所有换行符替换为空格
删除非数字字符
echo "Phone: 123-456-7890" | tr -cd '0-9' # 只保留数字 → 1234567890
# -c:匹配补集(非数字字符)
# -d:删除匹配的字符
将空格替换为制表符
echo "a b c" | tr ' ' '\t' # → a b c
加密/解密(ROT13)
echo "secret" | tr 'a-zA-Z' 'n-za-mN-ZA-M' # 加密 → frperg
echo "frperg" | tr 'a-zA-Z' 'n-za-mN-ZA-M' # 解密 → secret
删除控制字符(如 ^M)
cat file.txt | tr -d '\r' # 删除 Windows 换行符 ^M
统计单词数(通过空格压缩)
echo "how many words?" | tr -s ' ' | wc -w # → 3
# tr -s ' ':压缩连续空格为单个
# wc -w:统计单词数
生成随机字符串
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 10 # 生成10位随机字符串
#-dc:删除非字母数字字符
#head -c 10:截取前10个字符
注意事项:
- 字符集顺序敏感:
echo "abc" | tr 'abc' '123' # a→1, b→2, c→3
- 不支持正则表达式:复杂匹配需用 sed 或 awk。
- 多字节字符(如中文):可能无法正确处理,建议用 sed。
3.5、paste(合并文件的行)
paste 是 Linux 中一个高效的文本合并工具,用于 按行或列合并多个文件的内容,默认用制表符(Tab)分隔。它不修改原始文件,仅输出合并后的结果。
paste [选项] 文件1 文件2 ...
# 输入:可直接接文件名,或通过管道(|)传递文本。
# 输出:合并后的内容(默认以 Tab 分隔)。
常用选项:
-d
指定分隔符(默认是 Tab)-s
将文件按行合并(默认按列)-
从标准输入读取数据(通常结合管道使用)
经典案例:
合并两个文件(按列)
paste file1.txt file2.txt
#示例:
# file1.txt # file2.txt
apple red
banana yellow
# 合并后输出:
apple red
banana yellow
指定分隔符(-d)
paste -d ',' file1.txt file2.txt # 用逗号分隔
#输出:
markdown
apple,red
banana,yellow
合并多个文件
paste file1.txt file2.txt file3.txt
按行合并(-s)
paste -s file1.txt
#示例:
# file1.txt
apple
banana
# 合并后输出:
apple banana
#结合分隔符:
paste -s -d ',' file1.txt # 输出:apple,banana
从标准输入合并数据
cat file1.txt | paste - file2.txt
# 等效于:
paste file1.txt file2.txt
合并行和列(复杂场景)
paste -d ' ' -s file1.txt file2.txt
#示例:
# file1.txt # file2.txt
apple red
banana yellow
# 合并后输出:
apple banana
red yellow
高级用法:
结合 cut 和 paste 重组数据
cut -d ',' -f 1 data.csv | paste - - - # 每3行合并为1行
生成测试数据
seq 1 5 | paste -s -d '+' | bc # 计算1+2+3+4+5 → 15
快速创建表格
paste <(echo -e "Name\nAlice\nBob") <(echo -e "Age\n25\n30")
#输出:
markdown
Name Age
Alice 25
Bob 30
3.6、join(基于共同字段合并两个文件)
join 是 Linux 中用于 基于共同字段合并两个文件 的工具,类似于 SQL 的 JOIN 操作。它根据两个文件中指定的关键字段(默认是每行的第一个字段)进行匹配,并将匹配的行合并输出。
join [选项] 文件1 文件2
# 输入:两个已排序的文件(默认按字典序排序)。
# 输出:合并后的行,默认以空格分隔。
常用选项:
选项 | 描述 | 示例 |
---|---|---|
-a FILENUM | 输出未匹配的行(1=文件1,2=文件2) | join -a 1 file1 file2 |
-e STRING | 用指定字符串替换缺失字段 | join -e "NULL" file1 file2 |
-i | 比较时忽略大小写 | join -i file1 file2 |
-1 FIELD | 指定文件1的关联字段 | join -1 2 file1 file2 |
-2 FIELD | 指定文件2的关联字段 | join -2 3 file1 file2 |
-o FORMAT | 自定义输出格式 | join -o "1.1 2.2" file1 file2 |
-t CHAR | 指定字段分隔符 | join -t ',' file1 file2 |
-v FILENUM | 只输出未匹配的行 | join -v 1 file1 file2 |
经典案例:
基本合并:
# file1.txt # file2.txt
1 apple 1 red
2 banana 3 yellow
join file1.txt file2.txt
# 输出:1 apple red
指定分隔符
# file1.csv # file2.csv
1,apple 1,red
2,banana 3,yellow
join -t ',' file1.csv file2.csv
# 输出:1,apple,red
左连接
join -a 1 file1.txt file2.txt
# 输出:
# 1 apple red
# 2 banana
右连接
join -a 2 file1.txt file2.txt
# 输出:
# 1 apple red
# 3 yellow
自定义输出格式
join -o "1.1 1.2 2.2" file1.txt file2.txt
# 输出:1 apple red
处理缺失值
join -e "N/A" -a 1 file1.txt file2.txt
# 输出:
# 1 apple red
# 2 banana N/A
高级用法:
多字段连接
join -j 1 file1 file2 # 等同于使用-1 1 -2 1
反连接(只显示不匹配的行)
join -v 1 file1 file2 # 只显示文件1中不匹配的行
join -v 2 file1 file2 # 只显示文件2中不匹配的行
全外连接
join -a 1 -a 2 file1 file2
结合 sort 预处理**
join <(sort file1.txt) <(sort file2.txt)
4、文本排序和去重
4.1、sort(对文本行进行排序)
sort 是 Linux 系统中一个强大的文本排序工具,可以对文件内容或标准输入进行排序操作。它支持多种排序方式,包括按字典序、数值大小、月份、随机顺序等,并提供了丰富的选项来控制排序行为。
sort [选项] [文件]
排序控制选项:
-b
忽略行首空白字符-d
按字典序排序,只考虑字母、数字和空格-f
忽略大小写-g
按一般数值大小排序-h
按人类可读的数字大小排序(如 2K, 1G)-n
按数值大小排序-R
随机排序-r
逆序排序-V
按版本号自然排序
输出控制选项:
-c
检查文件是否已排序-k
指定排序的关键字段-m
合并已排序的文件-o
将结果输出到指定文件-s
稳定排序(保持相等记录的原始顺序)-t
指定字段分隔符-u
去除重复行(相当于 uniq)
使用示例:
基本排序
# 按字典序排序
sort file.txt
# 按数值大小排序
sort -n numbers.txt
# 逆序排序
sort -r file.txt
按指定字段排序
# 按第二列排序(默认空格分隔)
sort -k2 data.txt
# 按第三列数值大小排序
sort -k3n data.txt
# 使用冒号作为分隔符,按第二列排序
sort -t: -k2 /etc/passwd
高级排序
# 先按第三列数值排序,再按第一列字典序排序
sort -k3n -k1 data.txt
# 按人类可读的数字大小排序(如 2K, 1G)
sort -h sizes.txt
# 按版本号排序
sort -V versions.txt
检查和处理已排序文件
# 检查文件是否已排序
sort -c file.txt
# 合并多个已排序文件
sort -m file1.txt file2.txt
# 去除重复行
sort -u file.txt
输出控制
# 将结果输出到新文件
sort file.txt -o sorted.txt
# 稳定排序(保持相等记录的原始顺序)
sort -s -k2 data.txt
高级用法:
自定义排序
# 按第二列的第二个字符到第四个字符排序
sort -k2.2,2.4 data.txt
# 按第三列从开始到第一个空格前的部分排序
sort -k3.1,3.1 data.txt
处理特殊格式数据
# 处理CSV文件(逗号分隔)
sort -t, -k2 data.csv
# 处理制表符分隔的文件
sort -t$'\t' -k3 data.tsv
与其他命令结合
# 统计单词频率并排序
cat file.txt | tr ' ' '\n' | sort | uniq -c | sort -nr
# 找出最大的5个文件
ls -l | sort -k5nr | head -5
注意事项:
- sort 默认使用字典序排序,对数字排序需要使用 -n 选项
- 当处理大文件时,sort 会使用临时文件,可能占用较多磁盘空间
- 使用 -k 选项指定字段时,字段编号从1开始
- 对于包含特殊字符的文件,可能需要使用 -b 选项忽略空白字符
性能优化:
对于大文件排序,可以考虑以下优化方法:
# 设置缓冲区大小(单位为KB)
sort -S 50% file.txt # 使用50%的可用内存
# 指定临时文件目录(当/tmp空间不足时)
sort -T /mnt/bigdisk file.txt
# 并行排序(GNU sort特有)
sort --parallel=4 bigfile.txt
sort 命令是Linux文本处理工具箱中不可或缺的工具,掌握它的各种用法可以大大提高处理文本数据的效率。
4.2、uniq(去除重复行(通常与 sort 一起使用))
uniq 是 Linux 系统中用于 检测和删除连续重复行 的实用工具,常与 sort 命令配合使用来处理文本数据。
uniq [选项] [输入文件] [输出文件]
#如果不指定文件,uniq 会从标准输入读取数据。
核心功能:
- 删除连续重复行(默认行为)
- 统计重复次数(-c 选项)
- 只显示重复行/唯一行(-d 和 -u 选项)
常用选项:
选项 | 描述 | 示例 |
---|---|---|
-c | 在每行前加上重复次数 | uniq -c file.txt |
-d | 只显示重复行 | uniq -d file.txt |
-D | 显示所有重复行 | uniq -D file.txt |
-u | 只显示不重复行 | uniq -u file.txt |
-i | 忽略大小写 | uniq -i file.txt |
-f | N 跳过前 N 个字段比较 | uniq -f 2 file.txt |
-s N | 跳过前 N 个字符比较 | uniq -s 3 file.txt |
-w N | 只比较前 N 个字符 | uniq -w 5 file.txt |
使用示例:
基本用法:
# 原始文件内容
$ cat fruits.txt
apple
apple
banana
orange
orange
orange
grape
# 删除连续重复行
$ uniq fruits.txt
apple
banana
orange
grape
统计重复次数
$ uniq -c fruits.txt
2 apple
1 banana
3 orange
1 grape
只显示重复行
$ uniq -d fruits.txt
apple
orange
只显示唯一行
$ uniq -u fruits.txt
banana
grape
高级用法:
跳过前N个字段比较
# 原始文件
$ cat data.txt
1 John Doe
2 Jane Doe
3 Bob Smith
4 Alice Smith
# 跳过第一个字段比较
$ uniq -f 1 data.txt
1 John Doe
3 Bob Smith
结合sort处理非连续重复行
# 先排序使重复行相邻,再用uniq处理
$ sort file.txt | uniq -c
统计日志文件中IP出现次数
$ cat access.log | awk '{print $1}' | sort | uniq -c | sort -nr
192 192.168.1.1
156 192.168.1.2
89 192.168.1.3
注意事项:
- 只处理连续重复行:uniq 默认只删除连续的重复行,通常需要先使用 sort 命令
- 字段分隔:默认以空白字符(空格/Tab)分隔字
- 字符比较:-w 和 -s 选项对字符位置敏感
- 输出重定向:可以直接指定输出文件,但要注意不要与输入文件相同
4.3、shuf(随机打乱文本行)
shuf 是 Linux 系统中一个用于 生成随机排列 的实用工具,它可以随机打乱输入的行顺序,常用于数据采样、随机排序等场景。
shuf [选项] [文件]
# 如果不指定文件,shuf 会从标准输入读取数据。
核心功能:
- 随机打乱输入行顺序
- 从输入中随机选取指定数量的行
- 生成随机数序列
常用选项:
选项 | 描述 | 示例 |
---|---|---|
-e | 打乱指定的参数列表 | shuf -e A B C D |
-i | 生成指定范围的随机数 | shuf -i 1-100 |
-n | 输出指定数量的随机行 | shuf -n 5 file.txt |
-o | 将结果输出到指定文件 | shuf -o output.txt input.txt |
-r | 允许重复选择(可放回抽样) | shuf -rn 10 file.txt |
--random-source | 指定随机源文件 | shuf --random-source=/dev/urandom file.txt |
使用示例:
基本随机排序
# 打乱文件行顺序
shuf file.txt
# 打乱标准输入
seq 10 | shuf
随机选取行
# 从文件中随机选取3行
shuf -n 3 file.txt
# 从1-100中随机选取5个不重复数字
shuf -i 1-100 -n 5
生成随机数序列
# 生成1-10的随机排列
shuf -i 1-10
# 生成10个1-100的随机数(可能有重复)
shuf -i 1-100 -rn 10
打乱参数列表
# 打乱给定的参数
shuf -e 红 橙 黄 绿 青 蓝 紫
高级用法:
# 将打乱结果保存到新文件
shuf file.txt -o shuffled.txt
# 使用特定随机源(如硬件随机数生成器)
shuf --random-source=/dev/hwrng file.txt
# 创建随机密码(选取8个字符)
tr -dc 'A-Za-z0-9' < /dev/urandom | fold -w 8 | shuf -n 1
注意事项:
- 默认行为:shuf 默认输出所有输入行,只是顺序随机
- 随机性质量:默认使用伪随机数生成器,如需更高随机性可指定 --random-source
- 内存限制:shuf 会将所有输入加载到内存,处理大文件时需注意
- 重复采样:使用 -r 选项可进行可放回抽样(可能选择相同行多次)
常见问题:
如何确保真正的随机性?
# 使用系统的高质量随机源
shuf --random-source=/dev/random file.txt
Q2: 如何从大文件中高效随机取样?
bash
# 使用reservoir sampling算法(适合超大文件)
awk -v n=10 'BEGIN {srand()} rand() < n/++k {line[k-1]=$0} END {for (i=0;i<n;i++) print line[i]}' hugefile.txt
Q3: 如何创建随机文件名?
bash
# 生成8字符随机文件名
echo $(shuf -i 0-9 -rn 4)$(shuf -e {a..z} -rn 4) | tr -d ' '
5、文本统计
5.1、wc(统计行数、单词数和字符数)
wc(word count)是 Linux 系统中用于统计文件或输入流中字节数、字数、行数的实用工具。它是文本处理和数据分析的基础命令之一。
wc [选项] [文件...]
核心功能:
- 统计行数(-l)
- 统计单词数(-w)
- 统计字节数(-c)
- 统计字符数(-m)
常用选项:
选项 | 描述 | 示例 |
---|---|---|
-l | 只显示行数 | wc -l file.txt |
-w | 只显示单词数 | wc -w file.txt |
-c | 只显示字节数 | wc -c file.txt |
-m | 只显示字符数 | wc -m file.txt |
-L | 显示最长行的长度 | wc -L file.txt |
无选项 | 显示行数、单词数、字节数 | wc file.txt |
使用示例:
基本统计:
# 统计文件的行数、单词数和字节数
wc file.txt
# 输出示例:12 45 230 file.txt
# 表示:12行 45个单词 230字节
单独统计各项:
# 只统计行数
wc -l file.txt
# 只统计单词数
wc -w file.txt
# 只统计字节数
wc -c file.txt
# 只统计字符数(对多字节字符更准确)
wc -m file.txt
统计多个文件:
# 统计多个文件
wc file1.txt file2.txt
# 输出示例:
# 12 45 230 file1.txt
# 8 30 150 file2.txt
# 20 75 380 total
统计标准输入:
# 统计从管道输入的内容
cat file.txt | wc -l
# 统计命令输出的行数
ls -l | wc -l
高级用法:
# 统计当前目录下所有.txt文件的总行数
find . -name "*.txt" -exec wc -l {} +
# 统计文件中最长行的长度
wc -L file.txt
# 统计代码行数(排除空行)
grep -v '^$' code.py | wc -l
# 统计UTF-8编码的字符数(非字节)
iconv -f utf8 -t utf8 file.txt | wc -m
注意事项:
- 单词定义:wc 以空格、制表符或换行符作为单词分隔符
- 字符vs字节
- ASCII文本中字符数=字节数
- UTF-8文本中一个字符可能占多个字节
- 隐藏字符:换行符也会被计入字节/字符数
- 大文件处理:wc 可以高效处理超大文件
常见问题:
# 如何统计目录下所有文件的行数总和?
find . -type f -exec wc -l {} + | tail -1
#如何只显示统计数字而不显示文件名?
wc -l < file.txt
# 或者
cat file.txt | wc -l
#为什么字符数和字节数不同?
# 对于包含中文等多字节字符的文件
echo "中文" | wc -c # 输出7(UTF-8中每个中文占3字节+1换行符)
echo "中文" | wc -m # 输出3(2个字符+1换行符)
# 如何统计非空白行数?
grep -c '[^[:space:]]' file.txt
5.2、nl(为文本行添加行号)
nl 是 Linux 系统中用于 给文件添加行号 的实用工具,它比简单的 cat -n 提供了更强大的行号控制功能。
nl [选项] [文件]
# 如果不指定文件,nl 会从标准输入读取数据。
核心功能:
- 给文件内容添加行号
- 自定义行号格式
- 选择性给某些行编号
- 设置起始行号和增量
常用选项:
选项| 描述| 示例|
-b
| 指定哪些行需要编号| nl -b a file.txt
|
-v
| 设置起始行号| nl -v 10 file.txt
|
-i
| 设置行号增量| nl -i 2 file.txt
|
-s
| 设置行号分隔符| nl -s " " file.txt
|
-w
| 设置行号宽度| nl -w 3 file.txt
|
-n
| 设置行号对齐方式 |nl -n rz file.txt
|
-p
| 不重置逻辑页面的行号| nl -p file.txt
|
使用示例:
基本行号添加
# 给文件所有行添加行号(等同于 cat -n)
nl file.txt
# 从标准输入添加行号
cat file.txt | nl
指定行号样式
# 设置行号宽度为3,使用冒号分隔
nl -w 3 -s ": " file.txt
# 输出示例:
# 1: 第一行内容
# 2: 第二行内容
# 右对齐,前导零填充(-n rz)
nl -n rz file.txt
# 输出示例:
# 001 第一行内容
# 002 第二行内容
选择性编号
# 只给非空行编号
nl -b t file.txt
# 只给匹配正则的行编号
nl -b p^[A-Z] file.txt # 只给以大写字母开头的行编号
设置起始值和增量
# 从10开始编号,每次增加2
nl -v 10 -i 2 file.txt
# 输出示例:
# 10 第一行内容
# 12 第二行内容
# 14 第三行内容
高级用法:
# 给脚本添加行号并高亮显示
nl -w 3 -s " | " script.sh | highlight -O ansi --syntax bash
# 给日志文件添加行号,只显示错误行
nl -b pERROR system.log | grep ERROR
# 多文件合并并连续编号
nl -s " " -v 1 -i 1 file1.txt file2.txt
选项详解:
-b 选项(指定编号行类型)
a
给所有行编号t
只给非空行编号(默认)n
不编号p<regex>
只给匹配正则的行编号
-n选项(行号对齐)
ln
左对齐,无前导零rn
右对齐,无前导零rz
右对齐,前导零填充
注意事项:
- 默认行为:nl 默认只给非空行编号(相当于 -b t)
- 逻辑页面:nl 将输入视为逻辑页面,默认在每个逻辑页面重置行号(可用 -p 禁用
- 特殊字符:分隔符 -s 可以包含特殊字符如 \t(制表符)
- 大文件处理:nl 可以高效处理大文件
常见问题:
#如何显示绝对行号(包括空行)?
nl -b a file.txt
#如何让行号从1开始连续计数?
nl -b a -v 1 -i 1 -p file.txt
#nl 和 cat -n 有什么区别?
# cat -n 简单给所有行编号(包括空行)
cat -n file.txt
# nl 默认只给非空行编号,且提供更多格式控制
nl file.txt
#如何给grep结果添加行号?
grep -n "pattern" file.txt # grep自带简单行号
# 或者
grep "pattern" file.txt | nl -b a -v 1 -i 1
6、文本比较
6.1、diff(比较两个文件的差异)
diff 是 Linux 系统中用于 比较文件差异 的核心工具,它能逐行比较两个文件或目录的内容差异,是版本控制、补丁制作和代码审查的基础工具。
diff [选项] 文件1 文件2
diff [选项] 目录1 目录2
核心功能:
- 逐行比较文本文件差异
- 生成可读的差异报告
- 支持递归目录比较
- 输出可用于补丁的格式
常用选项:
选项 | 描述 | 示例 |
---|---|---|
-u | 统一格式输出(unified) | diff -u file1 file2 |
-c | 上下文格式输出(context) | diff -c file1 file2 |
-i | 忽略大小写差异 | diff -i file1 file2 |
-w | 忽略所有空白差异 | diff -w file1 file2 |
-b | 忽略空白字符差异 | diff -b file1 file2 |
-B | 忽略空行差异 | diff -B file1 file2 |
-r | 递归比较目录 | diff -r dir1 dir2 |
-q | 只显示文件是否不同 | diff -q file1 file2 |
-y | 并排格式显示差异 | diff -y file1 file2 |
--color | 彩色显示差异 | diff --color file1 file2 |
输出格式详解:
标准格式(默认)
2c2
< 原文件第二行内容
---
> 新文件第二行内容
# a = 添加(add)
# d = 删除(delete)
# c = 修改(change)
统一格式(-u)
--- file1 2023-01-01 00:00:00.000000000 +0800
+++ file2 2023-01-02 00:00:00.000000000 +0800
@@ -1,3 +1,3 @@
相同行
-删除行(红色)
+添加行(绿色)
相同行
上下文格式(-c)
*** file1 2023-01-01 00:00:00.000000000 +0800
--- file2 2023-01-02 00:00:00.000000000 +0800
***************
*** 1,3 ****
相同行
! 删除行
相同行
--- 1,3 ----
相同行
! 添加行
相同行
使用示例:
基本文件比较
# 简单比较两个文件
diff file1.txt file2.txt
# 彩色输出差异
diff --color file1.txt file2.txt
生成补丁文件
# 生成unified diff格式补丁
diff -u old_file new_file > changes.patch
# 应用补丁
patch < changes.patch
目录比较
# 递归比较两个目录
diff -r dir1 dir2
# 只显示有差异的文件名
diff -rq dir1 dir2
高级比较技巧
# 忽略空白差异比较C源代码
diff -wB file1.c file2.c
# 并排显示差异(适合终端查看)
diff -y file1.txt file2.txt
# 比较命令输出差异
diff <(command1) <(command2)
忽略特定内容差异
# 忽略大小写
diff -i file1 file2
# 忽略所有空白(包括空格/tab/空行)
diff -w file1 file2
# 自定义忽略模式(使用filterdiff等工具)
filterdiff -x '*.log' diff_output
使用技巧:
#结合git
git diff | diffstat # 查看变更统计
#统计差异:
diff -u file1 file2 | diffstat
#交互式查看:
diff -u file1 file2 | less
#比较压缩文件:
diff <(zcat file1.gz) <(zcat file2.gz)
#忽略特定行:
diff -I '^#' file1 file2 # 忽略注释行差异
注意事项:
- 二进制文件:默认会尝试文本比较,对二进制文件使用cmp更合适
- 大文件处理:超大文件比较可能消耗较多内存
- 编码问题:不同编码文件比较可能产生乱码,建议统一编码
- 符号链接:-r选项默认不跟踪符号链接,需配合-L选项
6.2、patch(应用差异文件)
patch 是 Linux 系统中用于 应用差异文件 的工具,它可以将 diff 命令生成的差异文件应用到原始文件上,实现文件的更新和版本控制。
patch [选项] [原始文件 [补丁文件]]
核心功能:
- 将 diff 生成的补丁应用到原始文件
- 支持多种补丁格式(unified, context, normal)
- 支持撤销已应用的补丁
- 批量处理多个文件的补丁
常用选项:
选项 | 描述 | 示例 |
---|---|---|
-pNUM | 剥离路径前缀层级 | patch -p1 < patchfile |
-i | 指定补丁文件 | patch -i changes.patch |
-R | 撤销补丁 | patch -R < patchfile |
-b | 创建备份文件 | patch -b < patchfile |
-E | 删除空文件 | patch -E < patchfile |
--dry-run | 试运行不实际修改 | patch --dry-run < patchfile |
-d | 指定工作目录 | patch -d /path/to/files < patchfile |
-N | 跳过已应用的补丁 | patch -N < patchfile |
-F NUM | 设置模糊匹配行数 | patch -F 3 < patchfile |
补丁文件格式:
Unified diff 格式(推荐)
diff
--- original.txt 2023-01-01
+++ modified.txt 2023-01-02
@@ -1,3 +1,3 @@
相同行
-删除行
+添加行
相同行
Context diff 格式
diff
*** original.txt 2023-01-01
--- modified.txt 2023-01-02
***************
*** 1,3 ****
相同行
! 删除行
相同行
--- 1,3 ----
相同行
! 添加行
相同行
使用示例:
基本补丁应用
# 应用补丁(自动检测补丁格式)
patch < changes.patch
# 指定补丁文件
patch -i changes.patch
# 应用到指定文件
patch original.txt < changes.patch
路径处理
# 剥离1层路径前缀(常见于源码补丁)
patch -p1 < changes.patch
# 补丁中路径:a/src/file.c → 应用为:src/file.c
# 指定工作目录
patch -d /path/to/source < changes.patch
安全操作
# 试运行(不实际修改文件)
patch --dry-run < changes.patch
# 创建备份文件(原始文件保存为.orig)
patch -b < changes.patch
# 自动删除空文件
patch -E < changes.patch
撤销补丁
# 撤销已应用的补丁
patch -R < changes.patch
# 带备份的撤销
patch -R -b < changes.patch
批量补丁处理
# 应用目录下所有补丁
for p in *.patch; do patch -p1 < "$p"; done
# 从git生成补丁并应用
git format-patch HEAD~1
git apply 0001-*.patch
高级技巧:
处理模糊匹配:
# 允许3行上下文不匹配
patch -F 3 < changes.patch
合并多个补丁:
cat patch1.patch patch2.patch | patch -p1
从压缩文件应用补丁:
zcat changes.patch.gz | patch -p1
创建反向补丁:
diff -u new.txt old.txt > revert.patch
内核源码补丁应用:
cd linux-5.x
patch -p1 < ../patch-5.x.y
常见问题解决:
补丁应用失败怎么办?
# 1. 检查路径是否正确(使用-p参数调整)
# 2. 检查文件版本是否匹配
# 3. 使用--verbose查看详细过程
patch --verbose -p1 < changes.patch
# 4. 手动合并冲突(会生成.rej文件)
如何创建补丁文件?
# 比较两个文件
diff -u old.txt new.txt > changes.patch
# 比较两个目录
diff -ruN old_dir/ new_dir/ > changes.patch
如何查看补丁内容?
# 查看补丁将修改的内容
patch -p1 --dry-run --verbose < changes.patch
# 或直接查看diff文件
less changes.patch
如何恢复原始文件?
# 如果使用了-b选项
cp file.txt.orig file.txt
# 或者撤销补丁
patch -R < changes.patch
6.3、cmp(逐字节比较两个文件)
cmp 是 Linux 系统中用于 逐字节比较两个文件 的工具,它比 diff 更底层,主要用于检测文件是否完全相同,或者找出第一个差异的位置。
cmp [选项] 文件1 文件2
核心功能
- 比较两个文件是否完全相同
- 找出第一个差异的字节位置和行号
- 支持限制比较长度
- 支持静默模式(只返回退出状态)
常用选项:
选项 | 描述 | 示例 |
---|---|---|
-l | 显示所有不同字节 | cmp -l file1 file2 |
-s | 静默模式(不输出) | cmp -s file1 file2 |
-n | 限制比较的字节数 | cmp -n 100 file1 file2 |
-i | 跳过指定字节开始比较 | cmp -i 10 file1 file2 |
-b | 显示不同的字节内容 | cmp -b file1 file2 |
使用示例:
基本比较
# 简单比较两个文件
cmp file1.bin file2.bin
# 输出示例:file1.bin file2.bin differ: byte 123, line 5
详细差异输出
# 显示所有不同的字节
cmp -l file1.bin file2.bin
# 输出示例:
# 123 12 56
# 表示第123字节,file1中是12(八进制),file2中是56(八进制)
脚本中使用(静默模式)
# 在脚本中检查文件是否相同
if cmp -s file1 file2; then
echo "文件相同"
else
echo "文件不同"
fi
部分比较
# 只比较前100个字节
cmp -n 100 file1.bin file2.bin
# 跳过前10个字节开始比较
cmp -i 10 file1.bin file2.bin
显示字节内容
# 显示第一个差异的字节内容
cmp -b file1.bin file2.bin
# 输出示例:file1.bin file2.bin differ: byte 123, line 5 is 12 ^J 56 ^H
输出解读:
默认输出
file1 file2 differ: byte XXX, line YYY
# XXX 是第一个差异的字节位置(从1开始计数)
# YYY 是第一个差异所在的行号
-l 选项输出
XXX AAA BBB
XXX 是字节位置(八进制)
AAA 是file1中的字节值(八进制)
BBB 是file2中的字节值(八进制)
高级用法:
比较进程输出
cmp <(command1) <(command2)
比较文件校验和
# 更高效的比较大文件方法
cmp -n $(stat -c%s file1) file1 file2
二进制文件补丁定位
# 找出二进制文件差异位置
cmp -l original.bin modified.bin > differences.list
自动化测试
# 验证文件是否与预期一致
expected="expected_output.bin"
actual="generated_output.bin"
if ! cmp -s "$expected" "$actual"; then
echo "测试失败:输出不符"
cmp -l "$expected" "$actual" | head -10 # 显示前10处差异
exit 1
fi
注意事项:
- 二进制安全:cmp 适合比较二进制文件,不会像 diff 那样将文件视为文本
- 性能:对于大文件,cmp 比 diff 更快,因为它不需要逐行分析
- 行号计算:行号是基于换行符(\n)计算的,可能与文本编辑器的行号不同
- 退出状态:
- 0:文件相同
- 1:文件不同
- 2:发生错误
常见问题:
比较两个目录下的同名文件?
for file in dir1/*; do
cmp -s "$file" "dir2/${file##*/}" || echo "${file##*/} 不同"
done
如何忽略文件开头的特定字节差异?
# 跳过文件前100字节比较
cmp -i 100 file1.bin file2.bin
如何找出两个二进制文件的所有差异?
cmp -l file1.bin file2.bin > differences.txt
# 然后可以分析differences.txt文件
6.4、comm(比较两个排序文件的行)
comm 是 Linux 系统中用于 逐行比较两个已排序文件 的工具,它能显示两个文件共有的行和各自独有的行。
comm [选项] 文件1 文件2
核心功能:
- 比较两个已排序文件的行
- 输出三列结果:
- 第1列:只在文件1中出现的行
- 第2列:只在文件2中出现的行
- 第3列:两个文件共有的行
常用选项:
选项 | 描述 | 示例 |
---|---|---|
-1 | 不显示第1列(文件1独有行) | comm -1 file1 file2 |
-2 | 不显示第2列(文件2独有行) | comm -2 file1 file2 |
-3 | 不显示第3列(共有行) | comm -3 file1 file2 |
--check-order | 检查输入是否已排序 | comm --check-order file1 file2 |
--nocheck-order | 不检查输入是否排序 | comm --nocheck-order file1 file2 |
--output-delimiter=STR | 设置自定义分隔符 | `comm --output-delimiter="` |
使用示例:
基本比较
# 文件1内容
$ cat file1.txt
apple
banana
orange
# 文件2内容
$ cat file2.txt
banana
grape
orange
# 比较两个文件
$ comm file1.txt file2.txt
apple
banana
orange
grape
#输出说明:
#apple(前面无制表符):只在file1.txt中存在
#grape(前面1个制表符):只在file2.txt中存在
#banana和orange(前面2个制表符):两个文件共有
选择性显示
# 只显示两个文件共有的行
$ comm -12 file1.txt file2.txt
banana
orange
# 只显示file1独有的行
$ comm -23 file1.txt file2.txt
apple
# 只显示file2独有的行
$ comm -13 file1.txt file2.txt
grape
处理未排序文件
# 先排序再比较
$ comm <(sort file1.txt) <(sort file2.txt)
# 或者强制比较未排序文件(不推荐)
$ comm --nocheck-order unsorted1.txt unsorted2.txt
自定义输出格式
# 使用自定义分隔符
$ comm --output-delimiter="|" file1.txt file2.txt
apple
|banana
||orange
|grape
高级用法:
比较命令输出
# 比较两个命令的输出
$ comm <(command1 | sort) <(command2 | sort)
找出新增/删除的行
# 比较新旧配置文件
$ comm -3 <(sort old.conf) <(sort new.conf)
统计行数
# 统计file1独有行数
$ comm -23 file1.txt file2.txt | wc -l
# 统计共有行数
$ comm -12 file1.txt file2.txt | wc -l
结合进程替换
# 比较两个压缩文件的内容
$ comm <(zcat file1.gz | sort) <(zcat file2.gz | sort)
注意事项:
- 输入文件必须已排序:除非使用–nocheck-order选项
- 制表符分隔:默认使用制表符分隔列,可用–output-delimiter修改
- 性能:对于大文件,先排序再比较可能消耗较多资源
- 退出状态:
- 0:成功
- 1:输入未排序且未使用–nocheck-order
- 2:发生错误
常见问题:
如何忽略大小写比较?
$ comm -i <(sort file1.txt | tr '[:upper:]' '[:lower:]') \
<(sort file2.txt | tr '[:upper:]' '[:lower:]')
如何比较两个目录下的文件列表?
$ comm <(ls dir1 | sort) <(ls dir2 | sort)
如何去除制表符显示?
$ comm file1.txt file2.txt | tr -d '\t'
7、文本转换
7.1、iconv(转换文件编码)
iconv 是 Linux 系统中用于字符编码转换的命令行工具,能够将文件或输入流的文本从一种编码格式转换为另一种编码格式(例如 UTF-8、GBK、ISO-8859-1 等)。
iconv -f 原编码 -t 目标编码 [输入文件] [-o 输出文件]
常用选项:
-f ENCODING
指定输入文件的原始编码(如 GBK, UTF-8)-t ENCODING
指定目标编码(如 UTF-8, ISO-8859-1)-o FILE
将转换结果输出到指定文件(默认输出到终端)-l
列出所有支持的编码格式-c
忽略无法转换的字符(静默丢弃)--verbose
显示转换过程中的详细信息
使用示例:
基本转换
#将 file.txt 从 GBK 编码转为 UTF-8:
iconv -f GBK -t UTF-8 file.txt -o output.txt
管道操作
结合管道处理其他命令的输出:
cat file.txt | iconv -f GBK -t UTF-8
忽略无效字符
跳过无法转换的字符(避免报错):
iconv -f GBK -t UTF-8//IGNORE file.txt
列出支持的编码
iconv -l
批量转换文件
#使用循环转换目录下所有 .txt 文件:
for file in *.txt; do
iconv -f GBK -t UTF-8 "$file" -o "converted_$file"
done
常见问题:
- 编码识别错误
- 若不确定文件原始编码,可使用 file -i 文件名 或 enca 具检测编码。
- 转换失败处理
- 尝试添加 //IGNORE 或 //TRANSLIT 后缀(如 UTF-8//IGNORE)。
- 使用 -c 选项忽略错误字符。
- 换行符问题
- 在 Windows 格式(CRLF)和 Linux 格式(LF)间转换时,可结合 dos2unix 或 sed 处理。
常见问题:
- 如果未指定 -o 输出文件,转换结果会直接打印到终端。
- 部分系统可能需要安装 GNU libiconv 库以支持更多编码。
- 对二进制文件使用 iconv 可能导致数据损坏。
7.2、dos2unix(将 Windows 换行符(CRLF)转换为 Unix 换行符(LF))
dos2unix 是 Linux 系统中用于将 Windows/DOS 格式的文本文件(CRLF 换行符 \r\n)转换为 Unix/Linux 格式(LF 换行符 \n)的命令行工具。以下是详细说明:
dos2unix [选项] 文件名
常用选项
-k
或--keepdate
保留文件的时间戳(不修改文件时间)-n
或--newfile
将转换结果输出到新文件(需指定输入和输出文件)-o
或--oldfile
直接覆盖原文件(默认行为)-q
或--quiet
静默模式(不显示警告信息)-V
或--version
显示版本信息-h
或--help
显示帮助文档
示例用法:
直接覆盖原文件
#将 file.txt 从 DOS 格式转换为 Unix 格式(直接修改原文件):
dos2unix file.txt
保留时间戳
#转换文件但保持修改时间不变:
dos2unix -k file.txt
生成新文件
#转换文件并输出到新文件(不修改原文件):
dos2unix -n input.txt output.txt
批量转换
#转换当前目录下所有 .txt 文件:
dos2unix *.txt
管道操作
#结合 cat 或其他命令使用:
cat dosfile.txt | dos2unix > unixfile.txt
常见问题:
文件权限问题
#若提示权限不足,可使用 sudo 或先修改文件权限:
chmod +w file.txt && dos2unix file.txt
二进制文件警告
#如果文件包含二进制数据(如图片),dos2unix 会提示跳过。强制转换可能导致文件损坏。
Mac 格式文件
#Mac 旧版文本使用 \r 作为换行符,需先转换为 Unix 格式:
tr '\r' '\n' < macfile.txt > unixfile.txt
安装方式:若系统中未安装,可通过包管理器安装:
sudo apt install dos2unix # Debian/Ubuntu
sudo yum install dos2unix # CentOS/RHEL
7.3、unix2dos(将 Unix 换行符(LF)转换为 Windows 换行符(CRLF))
unix2dos 是 Linux 系统中用于将 Unix/Linux 格式的文本文件(LF 换行符 \n)转换为 Windows/DOS 格式(CRLF 换行符 \r\n)的命令行工具。它是 dos2unix 的反向操作,常用于需要兼容 Windows 环境的场景。
unix2dos [选项] 文件名
常用选项:
-k
或--keepdate
保留文件的时间戳(不修改文件修改时间)-n
或--newfile
转换并输出到新文件(不覆盖原文件)-o
或--oldfile
直接覆盖原文件(默认行为)-q
或--quiet
静默模式(不显示警告信息)-V
或--version
显示版本信息-h
或--help
显示帮助文档
示例用法:
直接覆盖原文件(默认)
unix2dos file.txt
#将 file.txt 从 Unix 换行符(\n)转换为 Windows 换行符(\r\n),并覆盖原文件。
保留文件时间戳**
unix2dos -k file.txt
#转换文件,但保持文件的修改时间不变。
转换并输出到新文件**
unix2dos -n input.txt output.txt
#转换 input.txt 并保存为 output.txt,不修改原文件。
批量转换当前目录下所有 .txt 文件**
unix2dos *.txt
#将所有 .txt 文件转换为 Windows 格式。
结合管道操作
cat unixfile.txt | unix2dos > winfile.txt
#通过管道读取 unixfile.txt,转换后输出到 winfile.txt。
8、其它命令
8.1、tee(将输出同时写入文件和屏幕)
tee 是 Linux 中一个非常实用的命令,它能够同时将数据输出到屏幕(标准输出)和文件。名称来源于 T 型管道,可以将数据流分叉到两个方向。
command | tee [选项] 文件名
常用选项
-a
或--append
追加到文件而不是覆盖-i
或--ignore-interrupts
忽略中断信号-p
诊断写入非管道的错误--help
显示帮助信息--version
显示版本信息
使用示例:
基本用法:输出到屏幕并保存到文件
ls -l | tee directory_listing.txt
#这会显示 ls -l 的输出,同时将其保存到 directory_listing.txt 文件中。
追加到文件(不覆盖原有内容)
echo "New line" | tee -a existing_file.txt
同时输出到多个文件
dmesg | tee file1.txt file2.txt file3.txt
与 sudo 结合使用
echo "New line" | sudo tee /root/example.txt
#注意:直接使用 sudo echo 重定向到特权文件会失败,因为重定向是由 shell 执行的。使用 tee 可以解决这个问题。
忽略中断信号
yes | tee -i output.txt
#即使按 Ctrl+C,tee 也会继续运行。
捕获错误输出
(ls /nonexistent 2>&1) | tee error.log
#将标准错误重定向到标准输出,然后通过 tee 捕获。
高级用法:
与 grep 结合使用
ls -l /usr/bin | tee all_files.txt | grep python > python_files.txt
#保存完整列表到 all_files.txt,同时筛选出包含 "python" 的行到 python_files.txt。
监控日志文件
tail -f /var/log/syslog | tee syslog_copy.txt
#实时监控日志并保存副本。
记录命令执行过程
script -c "ls -l; df -h" | tee session.log
#记录完整的命令会话。
8.2、column(将文本格式化为列)
column 是 Linux 中一个用于格式化文本输出的实用工具,它能将输入数据组织成整齐的列,提高可读性。这个命令特别适合处理表格数据或需要对齐的文本。
column [选项] [文件名]
#如果不指定文件名,column 会从标准输入读取数据。
常用选项:
-t
自动创建表格,根据分隔符对齐列-s sep
指定输入字段分隔符(默认是空白字符)-c num
设置输出宽度为 num 个字符-o str
指定输出列分隔符(默认是两个空格)-N names
指定列名(与-t一起使用)-x
先填充行而不是列-l
显示列数后退出
使用示例:
基本表格格式化
echo -e "Name Age Gender\nJohn 25 Male\nLisa 30 Female" | column -t
# 输出:
markdown
Name Age Gender
John 25 Male
Lisa 30 Female
指定分隔符
echo -e "Name,Age,Gender\nJohn,25,Male\nLisa,30,Female" | column -s ',' -t
# 输出:
markdown
Name Age Gender
John 25 Male
Lisa 30 Female
自定义输出分隔符
echo -e "Name Age Gender\nJohn 25 Male\nLisa 30 Female" | column -t -o " | "
#输出:
markdown
Name | Age | Gender
John | 25 | Male
Lisa | 30 | Female
处理CSV文件
echo -e "ID,Name,Department\n101,John,IT\n102,Lisa,HR" | column -s ',' -t
#输出:
markdown
ID Name Department
101 John IT
102 Lisa HR
指定列名
echo -e "101 John IT\n102 Lisa HR" | column -t -N "ID,Name,Department"
#输出:
markdown
ID Name Department
101 John IT
102 Lisa HR
限制输出宽度
ls -l | head -5 | column -t -c 80
#将输出限制在80个字符宽度内。
高级用法:
处理/etc/passwd文件
cut -d: -f1,3,7 /etc/passwd | head -5 | column -s ':' -t
#输出前5个用户的用户名、UID和shell,以冒号分隔并格式化。
结合awk使用
df -h | awk '{print $1,$5,$6}' | column -t
# 格式化磁盘使用情况的输出。
处理多空格分隔的数据
echo -e "Name Age Gender\nJohn 25 Male\nLisa 30 Female" | column -t
#即使输入中的空格数量不一致,也能正确对齐。
注意事项:
column 命令不是所有Linux发行版都默认安装,可能需要安装bsdmainutils包:
sudo apt install bsdmainutils # Debian/Ubuntu
sudo yum install util-linux # CentOS/RHEL
对于非常大的文件,column 可能会消耗较多内存,因为它需要缓存所有数据来确定列宽。
当处理包含非常长字段的数据时,可能需要使用-c选项限制输出宽度。
column 主要适用于文本数据的格式化,不适合处理二进制数据。
8.3、fmt(格式化文本段落)
fmt 是 Linux 中一个简单但实用的文本格式化工具,用于重新格式化文本段落,使其具有统一的宽度和整齐的外观。它特别适合处理杂乱的文本文件或邮件内容。
fmt [选项] [文件名...]
#如果不指定文件名,fmt 会从标准输入读取数据。
常用选项:
-w width
或--width=width
设置输出行宽度(默认75个字符)-s
或--split-only
只拆分长行,不合并短行-t
或--tagged-paragraph
保持第一行缩进不变-c
或--crown-margin
保持前两行缩进不变-u
或--uniform-spacing
使用统一空格(一个空格)-p prefix
或--prefix=prefix
只处理以指定前缀开头的行
使用示例:
基本文本格式化
echo "This is a long line of text that needs to be wrapped to fit within a certain width for better readability." | fmt -w 40
#输出:
This is a long line of text that needs
to be wrapped to fit within a certain
width for better readability.
格式化文件内容
fmt -w 60 myfile.txt
#将myfile.txt中的文本重新格式化为每行约60个字符。
只拆分长行不合并短行
echo -e "Short line.\nThis is a very long line that needs to be split but the short lines should remain as they are." | fmt -s -w 30
#输出:
Short line.
This is a very long line that
needs to be split but the
short lines should remain as
they are.
保持缩进格式
echo -e " This is an indented paragraph.\n It should maintain its indentation when reformatted." | fmt -t -w 40
#输出:
This is an indented paragraph.
It should maintain its indentation
when reformatted.
处理带前缀的文本(如邮件回复)
echo -e "> This is quoted text.\n> It should be formatted separately.\nThis is regular text." | fmt -p '> ' -w 50
#输出:
> This is quoted text. It should be formatted
> separately.
This is regular text.
统一空格处理
echo "This text has irregular spacing." | fmt -u
#输出:
This text has irregular spacing.
高级用法:
格式化代码注释
cat source.c | awk '/\/\*/ {flag=1; print; next} /\*\// {flag=0; print; next} flag {print}' | fmt -w 60
#提取并格式化C语言源代码中的多行注释。
结合find处理多个文件
find . -name "*.txt" -exec fmt -w 72 {} -o {}.fmt \;
#批量格式化所有文本文件为72字符宽度,并保存为.fmt后缀的新文件。
格式化git提交信息
git log -1 --pretty=%B | fmt -w 50
# 将最后一次提交信息格式化为50字符宽度。
注意事项:
- fmt 会合并多个空格为一个(除非使用-u选项),并自动换行。
- 默认情况下,fmt会尝试合并短行,除非使用-s选项。
- 对于包含代码或格式化文本(如Markdown),使用fmt可能会破坏原有结构。
- 某些Linux发行版可能需要安装coreutils包来获取fmt命令。
- fmt处理中文等宽字符时可能需要考虑字符宽度问题。
8.4、fold(将文本行按指定宽度换行)
fold 是一个简单但实用的 Linux 命令行工具,用于将输入行按照指定宽度进行换行处理。与 fmt 不同,fold 只是机械地在指定位置插入换行符,不会考虑单词边界或段落结构。
fold [选项] [文件...]
#如果不指定文件,fold 会从标准输入读取数据。
常用选项:
-w width
或--width=width
设置行宽为 width 个字符(默认80)-b
或--bytes
按字节而非字符计数-s
或--spaces
在空格处换行(尽量保持单词完整)-c
或--characters
按字符计数(默认行为)--help
显示帮助信息--version
显示版本信息
使用示例:
基本换行操作
echo "这是一个非常长的行需要被折叠处理" | fold -w 10
#输出:
markdown
这是一个非
常长的行需
要被折叠处
理
处理文件内容
fold -w 50 long_text.txt
#将 long_text.txt 文件中的每行截断为50个字符宽度。
在空格处换行(保持单词完整)
echo "This is a sentence that should break at spaces" | fold -w 15 -s
#输出:
markdown
This is a
sentence that
should break
at spaces
按字节计数(处理多字节字符)
echo "日本語の文章" | fold -w 6 -b
#输出:
日本
語の
文章
注意:这里每个汉字占3个字节,所以实际显示可能不如预期。
结合其他命令使用
ls -l /usr/bin | fold -w 80
#将 ls -l 的输出限制为每行80个字符。
高级用法:
格式化代码行
cat long_line_code.py | fold -w 79 -s
#将Python代码行限制为PEP 8建议的79字符宽度。
处理CSV数据
echo "name,description,price" | fold -w 10 -s
#输出:
markdown
name,desc
ription,
price
#注意:这会破坏CSV结构,仅作演示。
创建文本边框:
echo "This text will be framed" | fold -w 20 | sed 's/^/| /; s/$/ |/' | sed '1i\+--------------------+\' | sed '$a\+--------------------+'
#输出:
markdown
+--------------------+
| This text will be |
| framed |
+--------------------+
注意事项:
- 默认情况下,fold 会严格在指定位置换行,不考虑单词完整性(除非使用 -s 选项)。
- 对于包含多字节字符(如中文、日文)的文本,使用 -b 选项可能产生意外结果。
- fold 不会合并短行,只是将长行分割。
- 与 fmt 不同,fold 不会重新排列文本,只是简单的换行处理。
- 某些系统上可能需要安装 coreutils 包来使用 fold。
fold 命令特别适合需要精确控制行宽的场景,如:
- 准备要打印的文本
- 格式化日志文件
- 处理需要固定宽度的文本输出
- 在脚本中预处理文本数据