Linux运维——文本处理

Linux文本处理

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忽略 .gitignoreag --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 成功才执行 command2
  • command1 || 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

注意事项:

  1. 标签名称不能包含空格或特殊字符
  2. 分支命令会改变 sed 的正常执行流程
  3. 复杂的分支逻辑可能难以调试,建议先在小样本上测试
  4. 某些 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脚本规则如下:

  1. 在命令的末尾不能有任何空白或文本
  2. 如果在一行中有多个命令,要用分号分隔
  3. 以#开头的行为注释行,且不能跨行
#这将按照 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. \(..\)用于匹配子串,对于匹配到的第一个子串标记为\1,依次类推
  2. 未定义\(..\)时,效果等同于&标记
#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

注意事项:

  1. sort 默认使用字典序排序,对数字排序需要使用 -n 选项
  2. 当处理大文件时,sort 会使用临时文件,可能占用较多磁盘空间
  3. 使用 -k 选项指定字段时,字段编号从1开始
  4. 对于包含特殊字符的文件,可能需要使用 -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
-fN 跳过前 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

注意事项:

  1. ​只处理连续重复行:uniq 默认只删除连续的重复行,通常需要先使用 sort 命令
  2. ​字段分隔:默认以空白字符(空格/Tab)分隔字
  3. ​字符比较:-w 和 -s 选项对字符位置敏感
  4. 输出重定向:可以直接指定输出文件,但要注意不要与输入文件相同

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 会从标准输入读取数据。

核心功能:

  1. 给文件内容添加行号
  2. 自定义行号格式
  3. 选择性给某些行编号
  4. 设置起始行号和增量

常用选项:
选项| 描述| 示例|
-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 右对齐,前导零填充

注意事项:

  1. 默认行为:nl 默认只给非空行编号(相当于 -b t)
  2. 逻辑页面:nl 将输入视为逻辑页面,默认在每个逻辑页面重置行号(可用 -p 禁用
  3. ​特殊字符:分隔符 -s 可以包含特殊字符如 \t(制表符)
  4. 大文件处理: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

核心功能:

  1. ​逐行比较文本文件差异
  2. 生成可读的差异报告
  3. 支持递归目录比较
  4. 输出可用于补丁的格式

常用选项:

选项描述示例
-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  # 忽略注释行差异

注意事项:

  1. 二进制文件:默认会尝试文本比较,对二进制文件使用cmp更合适
  2. 大文件处理:超大文件比较可能消耗较多内存
  3. 编码问题:不同编码文件比较可能产生乱码,建议统一编码
  4. 符号链接:-r选项默认不跟踪符号链接,需配合-L选项

6.2、patch(应用差异文件)

patch 是 Linux 系统中用于 ​应用差异文件 的工具,它可以将 diff 命令生成的差异文件应用到原始文件上,实现文件的更新和版本控制。

patch [选项] [原始文件 [补丁文件]]

核心功能:

  1. ​将 diff 生成的补丁应用到原始文件
  2. 支持多种补丁格式(unified, context, normal)​
  3. 支持撤销已应用的补丁
  4. 批量处理多个文件的补丁

常用选项:

选项描述示例
-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

核心功能

  1. ​比较两个文件是否完全相同
  2. 找出第一个差异的字节位置和行号
  3. 支持限制比较长度
  4. 支持静默模式(只返回退出状态)​

常用选项:

选项描述示例
-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字符宽度。

注意事项:

  1. fmt 会合并多个空格为一个(除非使用-u选项),并自动换行。
  2. 默认情况下,fmt会尝试合并短行,除非使用-s选项。
  3. 对于包含代码或格式化文本(如Markdown),使用fmt可能会破坏原有结构。
  4. 某些Linux发行版可能需要安装coreutils包来获取fmt命令。
  5. 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            |
+--------------------+

注意事项:

  1. 默认情况下,fold 会严格在指定位置换行,不考虑单词完整性(除非使用 -s 选项)。
  2. 对于包含多字节字符(如中文、日文)的文本,使用 -b 选项可能产生意外结果。
  3. fold 不会合并短行,只是将长行分割。
  4. 与 fmt 不同,fold 不会重新排列文本,只是简单的换行处理。
  5. 某些系统上可能需要安装 coreutils 包来使用 fold。

fold 命令特别适合需要精确控制行宽的场景,如:

  • 准备要打印的文本
  • 格式化日志文件
  • 处理需要固定宽度的文本输出
  • 在脚本中预处理文本数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值