Linux 文件内容处理
提取数据列
可以使用 cut
命令按行提取数据并删除所需部分,命令格式如下:
cut -d '分隔字符' -f 编号
cut -c 字符范围
可用参数如下:
参数 | 说明 |
---|---|
-d | 后面接分隔字符,与 -f 一起使用。 |
-f | 选取被切割后的第几段数据。 |
-c | 以字符为单位取出固定字符区间。 |
例如以 :
为分隔符,取出 PATH
变量第 3 和第 5 段:
[root@101c7 abc]$ echo $PATH | cut -d ":" -f 3,5
/usr/sbin:/root/bin
将 export
输出信息取得第 12 个字符以后的所有字符串:
[root@101c7 abc]$ export|head -4;echo "-----";export | cut -c 12- | head -4
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="101c7"
-----
HISTCONTROL="ignoredups"
HISTSIZE="1000"
HOME="/root"
HOSTNAME="101c7"
如果要选取的值是 12 到 20 个字符,那么使用 cut -c 12-20
。
抓取数据
使用 grep 则是分析一行信息,有需要的信息则将整行取出.简单语法如下:
grep [-acinv] '查找字符串' 文件名
grep -[AB] '查找字符串' 文件名
可用参数如下:
参数 | 说明 |
---|---|
-a | 将二进制文件以 text 文件的方式查找数据 |
-c | 计算找到 ‘查找字符串’ 的次数 |
-i | 忽略大小写 |
-n | 输出行号 |
-v | 反向选择 |
-E | 使用扩展正则表达式,默认使用基础正则表达式 |
-P | 使用 Perl 正则表达式 |
-F | 关闭正则表达式模式,将所有的字母都看作单词 |
-A/Bn | 列出找到结果的后/前 n 行 |
例如取出 /etc/man_db.conf 中含有 MANPATH 的行:
[root@101c7 ~]$ grep 'MANPATH' /etc/man_db.conf
# MANDATORY_MANPATH manpath_element
# MANPATH_MAP path_element manpath_element
# every automatically generated MANPATH includes these fields
忽略大小写,使用扩展正则表达式搜索打印出以 pw 开头的行,并显示行号:
[root@101c7 ~]$ cat anaconda-ks.cfg | grep -E -n -i '^pw.*'
45:pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
46:pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
47:pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
向搜索以 # 开头以 s 结尾的行:
[root@101c7 ~]$ grep -E -i -vn '^#.*s$' anaconda-ks.cfg
1:#version=DEVEL
2:# System authorization information
3:auth --enableshadow --passalgo=sha512
排序命令
使用 sort
命令能对文件内容进行排序。该命令的主要参数包括:
参数 | 说明 |
---|---|
-f | 忽略大小写差异; |
-b | 忽略最前面的空格; |
-M | 以月份的名字来排序; |
-n | 使用纯数字进行排序; |
-r | 反向排序; |
-u | 去除重复行; |
-t | 分隔符,默认是 TAB; |
-k | 以哪个分割区间来进行排序。 |
例如,将 passwd
文件内容按第一个字符排序:
[root@101c7 ~]$ cat /etc/passwd | sort | head -4
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
以 :
为分隔符,按第 3 列(数字)排序。也可以使用 -k 3,4
参数来先按第三列排序,再按第四列排序:
[root@101c7 ~]$ cat /etc/passwd | sort -t ':' -k 3 -n | head -5
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
如果要统计重复数据,可以使用 uniq
命令。需要注意的是,uniq
的输入必须是有序的。例如,使用 -c
参数统计用户登录次数,再以从少到多排序:
[root@101c7 ~]$ last | cut -d ' ' -f 1 | sort | uniq -c | sort -t ' ' -k 1 -n
1
1 wtmp
3 reboot
13 root
统计文件信息
使用 wc
命令来统计文件信息,包括行数、单词数和文件大小。该命令可用的选项包括:
参数 | 说明 |
---|---|
-l | 查询文件内容行数; |
-w | 查询文件单词数; |
-c | 查询文件大小(单位 B)。 |
默认参数为 -lwc
。例如,查询文件 anaconda-ks.cfg
的行数、单词数和大小:
[root@101c7 ~]$ wc anaconda-ks.cfg
48 122 1260 anaconda-ks.cfg
字符转换命令
可以使用 tr
命令删除一段信息中的文字,或进行文字信息的替换。该命令可用的参数包括:
参数 | 说明 |
---|---|
-d | 删除信息中的字符串; |
-s | 替换掉重复的字符。 |
例如,将 last
命令输出的信息中所有小写字母转换为大写:
[root@101c7 ~]$ last | tr '[a-z]' '[A-Z]'
ROOT TTY1 SAT SEP 11 09:35 STILL LOGGED IN
ROOT PTS/1 192.168.2.101 SAT SEP 11 08:58 STILL LOGGED IN
删除所有 passwd
文件中的 DOS 断行符 \r
并另存为 px.txt
:
[root@101c7 ~]$ cat /etc/passwd | tr -d '\r' > px.txt
转换 Tab 为空格
在 Linux 中,默认每隔 8 个字符有一个制表位(Tab Stop)。可以使用 col
命令将文件中的 Tab 转换成对等的空格。例如:
[root@101c7 ~]$ cat -A /etc/man_db.conf | grep "#M"
#MANDATORY_MANPATH ^I^I^I/usr/src/pvm3/man$
#MINCATWIDTH^I80$
#MAXCATWIDTH^I80$
[root@101c7 ~]$ cat /etc/man_db.conf | col -x | cat -A | grep "#M"
#MANDATORY_MANPATH /usr/src/pvm3/man$
#MINCATWIDTH 80$
#MAXCATWIDTH 80$
以上命令将制表位转换成了等效的空格,从而消除了 ^I
的干扰。
另外,还可以使用 expand
命令将 Tab 转换成空格。例如,将 /etc/man_db.conf
文件中的制表位设置为 1,并将 Tab 转换成空格:
[root@101c7 ~]$ grep "#M" /etc/man_db.conf| expand -t 1
#MANDATORY_MANPATH /usr/src/pvm3/man
#MINCATWIDTH 80
#MAXCATWIDTH 80
如果需要将行开头的空格转换成 Tab,可以使用 unexpand
命令。该命令不会操作行中间的空格,因为大多数时候,只需要使用 unexpand
程序进行缩进。您还可以使用 -a
选项将所有空格替换为 Tab。
转换断行符
在 Windows 中,文本文件的换行符是 CRLF
(\r\n
),而在 Linux 下则使用 LF
这个换行符。如果在 Linux 环境下执行 Windows 格式的脚本,可能会出现无法执行的错误。
可以通过 Notepad++ 的扩展搜索功能,将 \r 全部替换掉。也可以使用 dos2unix
和 unix2dos
命令来转换文本文件中的换行符:
[root@101c7 ~]$ dos2unix -k root.txt
dos2unix: converting file root.txt to Unix format ..
格式化行
如果需要将长行分隔成短行,可以使用 fold
命令。例如,将 anaconda-ks.cfg
文件中的行宽设置为 10 并且不分离单词:
[root@server3 ~]$ fold -s -w 10 anaconda-ks.cfg
#version=D
EVEL
# System
authorizat
格式化段落
如果需要将段落中的各行连接在一起,使段落尽可能短小和紧凑,可以使用 fmt
命令。该命令假定段落由空行分隔,因此一个段落就是一个或多个连续的文本行,不包含空格。
例如,将文本文件 anaconda-ks.cfg
按照行宽 50 个字符重新格式化段落,并合并连续的空格:
[root@server3 ~]$ fmt -u -w 50 anaconda-ks.cfg
#version=DEVEL # System authorization information
auth --enableshadow --passalgo=sha512 # Use
编码转换
可以使用 locale
命令查看与系统编码相关的设置。例如:
[root@101c7 ~]$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
如果需要修改系统编码以处理乱码问题,只需要重新定义对应的变量并导出即可。例如:
[root@101c7 ~]$ export LANG=en_US.UTF-8 ; locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
如果需要转换文件编码,可以使用 iconv
命令将文件编码转换为另一种格式。例如,将 1.txt
文件的原始编码 big5
转换为 UTF-8
:
[root@101c7 4]$ iconv -f big5 -t utf8 1.txt -o 1utf8.txt
[root@101c7 4]$ file 1utf8.txt
1utf8.txt: ASCII text
另外,还可以使用 iconv
命令将繁体中文转换为简体中文。例如,将 1.txt
中的繁体中文转换为简体中文 GB2312
编码格式,并将结果保存到 1.gb.txt
文件中:
[root@101c7 4]$ iconv -f utf8 -t big5 1.txt | iconv -f big5 -t gb2312 | iconv -f gb2312 -t utf8 -o 1.gb.txt
文件合并
可以使用 join
命令将两个文件中有相同数据的那一行加在一起。例如,将 passwd
与 shadow
相关的数据整合成一列:
[root@101c7 ~]$ join -t ':' /etc/passwd /etc/shadow
bin:x:1:1:bin:/bin:/sbin/nologin:*:17632:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:17632:0:99999:7:::
adm:x:3:4:adm:/var/adm:/sbin/nologin:*:17632:0:99999:7:::
还可以使用 paste
命令将两个文件按行拼接在一起,用 Tab 分隔两个文件的行。例如:
[root@101c7 ~]$ paste /etc/passwd /etc/shadow | head -3
bin:x:1:1:bin:/bin:/sbin/nologin bin:*:17632:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:17632:0:99999:7:::
以上命令将 passwd
与 shadow
两个文件的每一行按顺序拼接在一起,并用 Tab 分隔两个文件的行。
文件切割
可以使用 split 命令将大文件分割成小文件,参数如下:
参数 | 说明 |
---|---|
-b |
以指定大小进行切割 |
-l |
以行数来进行切割 |
-d |
以两位的数字而不是字母作为后缀 |
-a |
指定在后缀中使用的数字或字符的数量 |
PREFIX |
代表前导符,可作为切割文件的前导文字 |
例如将 test.iso
切割成每个文件大小为 5M:
[root@101c7 sdb4m]$ split -b 5M test.iso file.sp | ll | grep 'file'
-rw-r--r--. 1 root root 5242880 Sep 11 12:35 file.spaa
-rw-r--r--. 1 root root 5242880 Sep 11 12:35 file.spab
-rw-r--r--. 1 root root 5242880 Sep 11 12:35 file.spac
-rw-r--r--. 1 root root 5242880 Sep 11 12:35 file.spad
可以使用数据流重定向来合并切割后的文件:
[root@101c7 sdb4m]$ cat file1.spa* >> test1.iso;ll | grep 'test'
-rw-r--r--. 1 root root 20971520 Sep 11 12:38 test1.iso
-rw-r--r--. 1 root root 20971520 Sep 11 12:33 test.iso
如果不带参数,split
命令会以 1000 行作为切割条件。可以使用 -l
选项指定每 5 行记录成一个文件:
[root@101c7 sdb4m]$ ls -la | split -l 10 - lsla;wc -l lsla*
10 lslaaa
3 lslaab
13 total
一般来说,如果需要标准输入输出且没有文件,只有 -
时,-
就被当成标准输入或标准输出。
文件比较
在 Linux 系统中,比较文件可以使用 diff
命令。diff
命令会输出将左边的文件转换为右边的文件所需的修改内容。
命令格式为:diff [-bBi] 要比较的文件 基准文件
参数:
参数 | 说明 |
---|---|
-b | 忽略一行中仅有多个空白的区别,例如"a man"与"a man"视为等同 |
-B | 忽略空白行的区别 |
-i | 忽略大小写 |
例如,比较 c.cfg
和 cnew.txt
两个文件的区别:
[root@101c7 sdb4m]$ cat c.cfg
abcaca
/root/etc/
1.4
1a4
[root@101c7 sdb4m]$ cat cnew.cfg
abcaca
/root/etc
1.4
[root@101c7 sdb4m]$ diff c.cfg cnew.cfg
2c2
< /root/etc/
---
> /root/etc
4d3
< 1a4
比较结果说明如下:
行 | 值 | 说明 |
---|---|---|
1 | 2c2 | 左边和右边比第 2 行不一样(c=change 改变,d=delete 删除,a=append 追加) |
2 | < /root/etc/ | 显示左边文件不同的第 2 行内容 |
3 | — | 左右两个文件区分显示的分隔符 |
4 | > /root/etc | 显示右边文件不同的第 2 行内容 |
5 | 4d3 | 显示左边第 4 行和右边第 3 行比不同(d 代表删除) |
6 | < 1a4 | 显示左边文件第 4 行内容,而右边第 4 行不存在(被删除) |
可以直接将文件比较的区别制作成补丁文件(也叫差分),供要比较的文件使用升级。优点是反升级和升级一样方便。制作补丁参数为 -Naur:
[root@101c7 sdb4m]$ diff -Naur c.cfg cnew.cfg > c.patch;cat c.patch
--- c.cfg 2021-09-12 05:52:16.000000000 -0400
+++ cnew.cfg 2021-09-12 13:25:05.000000000 -0400
@@ -1,4 +1,3 @@
abcaca
-/root/etc/
+/root/etc
1.4
-1a4
提供给左侧文件使用的补丁内容:
行 | 值 | 说明 |
---|---|---|
1 | — c.cfg | 左边文件信息,— 表示旧文件 |
2 | +++ cnew.cfg | 右边文件信息,+++ 表示新文件 |
3 | @@ -1,4 +1,3 @@ | 修改数据的界定范围,旧文件在 1-4 行,新文件在 1-3 行 |
4 | abcaca | 第一行内容,内容前面没有符号表示不需要变动 |
5 | -/root/etc/ | 左侧文件第二行内容。减号 - 表示删除此行 |
6 | +/root/etc | 右侧文件第二行内容。加号 + 表示增加此行 |
7 | 1.4 | 第三行内容 |
8 | -1a4 | 左侧文件第四行内容,- 表示要删除此行 |
打文件补丁使用 patch
命令,参数为 -pN
,其中 N 为数字,表示取消几层目录的意思。
例如打补丁 c.patch:
[root@101c7 sdb4m]$ patch -p0 <c.patch ; cat c.cfg
patching file c.cfg
abcaca
/root/etc
1.4
恢复旧文件内容使用参数 -R -pN
:
[root@101c7 sdb4m]$ patch -R -p0 <c.patch ; cat c.cfg
patching file c.cfg
abcaca
/root/etc/
1.4
1a4
也可以用 diff
来比较目录下的区别。例如比较不同挂载点下的 lost+found 目录:
[root@101c7 sdb4m]$ diff /root/sdb4m/lost+found/ /ext333/lost+found/
Only in /root/sdb4m/lost+found/: 1
Only in /root/sdb4m/lost+found/: 2
相对于 diff
以行为单位比较,cmp
则是以字节为单位去比较,因此可以比较任何类型的文件。例如还是比较 c.cfg 与 cnew.cfg:
[root@101c7 sdb4m]$ cmp c.cfg cnew.cfg
c.cfg cnew.cfg differ: byte 17, line 2
其结果显示两个文件不同点在第 2 行,第 17 个字节处。