文件文本操作
命令 含义 grep
在文件中查找符合正则表达式的行。 cut
从文件中提取列。 paste
追加列。 tr
将字符翻译成其他字符。 expand,``unexpand
在制表符和空格之间转换。 sort
按各种标准对文本行进行排序。 uniq
在文件中定位相同的行。 tee
复制文件并在标准输出上同时打印它。
Linux最大的优点就是文本操作:我们通过应用变换,将文本文件(或标准输入)调整到所需的形式,这个操作常常是在管道中进行的。任何读取标准输入和写入标准输出的程序都属于这个范畴,这里我们将介绍一些最重要的工具。
grep
stdin stdout - file -- opt --help --version
grep [选项] 模式 [文件]
grep
(grep) 命令是Linux工具库中最常用、最强大的工具之一。它的基本理念很简单:给定一个或多个文件,打印出所有符合特定正则表达式模式的行。例如,如果一个文件 randomlines(随机行) 包含以下行:
棕色狐狸快速的跳过去了!
我妈妈刚给我们煎了九个煎饼。
电影在十一点。
如果我们搜索包含“煎饼”的所有行,我们得到:
→ grep pancake randomlines
我妈妈刚给我们煎了九个煎饼。
现在我们用一个正则表达式来匹配以感叹号结尾的行:
→ grep '\!$' randomlines
棕色狐狸快速的跳过去了!
grep
(grep) 可以使用两种不同类型的正则表达式,称为 basic(基本) 和 extended(扩展)。基本语法在 Table 2 中。学习正则表达式是非常值得的。很多Linux程序也使用它们,比如 sed
(sed) 和 perl
(perl)。
有用的选项
-v
只打印不符合正则表达式的行。 -l
只打印包含匹配行的文件的名称,而不是行本身。 -L
只打印不包含匹配行的文件的名称。 -c
只打印匹配行的计数。 -n
在每一行匹配的输出前面,打印其原始行号。 -b
在每一行匹配的输出前面,打印该行在输入文件中的字节偏移。 -i
大小写不敏感匹配。 -w
只匹配完整的单词(即,与整个正则表达式匹配的单词)。 -x
只匹配完整的行(即,与整个正则表达式匹配的行)。覆盖 -w
。-A
N
在每个匹配行后,打印其文件中的下一个 N
行。-B
N
在每个匹配行前,打印其文件中的前一个 N
行。-C
N
与 -A N
-B N
相同:打印每个匹配行上方 和 下方的 N
行(来自原始文件)。--color=always
用颜色突出显示匹配的文本,以提高可读性。 -r
递归搜索目录及其子目录中的所有文件。 -E
使用扩展正则表达式。参见 egrep
(egrep)。-F
使用固定字符串列表而非正则表达式。参见 fgrep
(fgrep)。
egrep
stdin stdout - file -- opt --help --version
egrep [选项] 模式 [文件]
egrep
(egrep) 命令就像 grep
(grep),但是使用不同的(“扩展的”)语言进行正则表达式。它与 grep -E
是相同的。
表达式 含义 .
任意单一字符。 [...]
匹配此列表中的任意单一字符。 [^...]
匹配此列表中不存在的任意单一字符。 (...)
分组。 |
` ^
行首。 $
行尾。 \<
单词的开始。 \>
单词的结束。 [:alnum:]
任何字母数字字符。 [:alpha:]
任何字母字符。 [:cntrl:]
任何控制字符。 [:digit:]
任何数字。 [:graph:]
任何图形字符。 [:lower:]
任何小写字母。 [:print:]
任何可打印字符。 [:punct:]
任何标点符号。 [:space:]
任何空格字符。 [:upper:]
任何大写字母。 [:xdigit:]
任何十六进制数字。 *
一个或多个重复的正则表达式。 \+
+
正则表达式重复一次或多次。\?
?
正则表达式出现零次或一次。\{
n
\}
{
n
}
正则表达式重复*n
*次。\{
n
,\}
{
n
,}
正则表达式重复*n
*次或更多次。\{
n
,
m
\}
{
n
,
m
}
正则表达式重复次数在*n
到m
(含)之间,n
* <
*m
*。\
c
字符* c
的字面值,即使c
是特殊的正则表达式字符。例如,使用 * 来匹配星号或者 \ 来匹配反斜杠。或者,将字面字符放在方括号中,比如 [] 或 []。
GREP 和行结束字符
当你使用 grep
(grep) 匹配行尾($
)时,如果文本文件是在Microsoft Windows或Mac OS X系统上创建的,可能会出现奇怪的结果。每个操作系统对行结束的标准都不同。在Linux上,文本文件中的每一行都以一个换行符结束(ASCII 10)。在Windows上,文本行以回车(ASCII 13)结束,后面跟着一个换行符。而在OS X上,一个文本文件可能只用换行符或回车符结束每一行。如果 grep
不能正确匹配行尾,可以使用 cat -v
检查非Linux的行尾字符,它会将回车符显示为 ^M
:
→ cat -v dosfile.
哎呀!这个文件似乎在每行的结尾处使用了^M
在换行符之前有回车符。^M
要删除回车符,可以使用 tr -d
命令:
→ tr -d '\r' < dosfile. > linuxfile.
→ cat -v linuxfile.
哎呀!这个文件似乎在每行的结尾处使用了
在换行符之前有回车符。
fgrep
stdin stdout - file -- opt --help --version
fgrep [选项] [固定字符串] [文件]
fgrep
(fgrep) 命令就像 grep
(grep),但是它接受的是由换行符分隔的固定字符串列表,而不是正则表达式。它与 grep -F
是相同的。例如,如果你有一个每行都是字符串的字典文件:
→ cat my_dictionary_file
aardvark
aback
abandon
...
你可以方便地在一组输入文件中搜索这些字符串:
→ fgrep -f my_dictionary_file story
a little aardvark who went to
visit the abbot at the abbey.
通常,你会使用小写的 -f
选项让 fgrep
从文件中读取固定字符串。你也可以使用引号在命令行中读取固定字符串,但这有点复杂。要在文件中搜索字符串“one”、“two”和“three”,你需要输入:
→ fgrep 'one 注意我们在输入换行符
two
three' myfile
当搜索*和{等非字母数字字符时,fgrep
很方便,因为它们会被当作字面值,而不是正则表达式字符。
cut
stdin stdout - file -- opt --help --version
cut -(b|c|f)range [选项] [文件]
cut
(cut) 命令从文件中提取文本的列。“列”是由字符偏移定义的(例如,每行的第19个字符):
→ cut -c19 myfile
或者由字节偏移定义(如果你的语言有多字节字符,那么字节和字符是不同的):
→ cut -b19 myfile
或者由分隔字段定义(例如,在一个逗号分隔的文件data.csv中的每一行的第五个字段):
→ cat data.csv
one,two,three,four,five,six,seven
ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN
1,2,3,4,5,6,7
→ cut -f5 -d, data.csv
five
FIVE
5
你不仅限于输出一个单列:你可以给出范围(3-16
),逗号分隔序列(3,4,5,6,8,16
)或两者都有(3,4,8-16
)。对于范围,如果你省略了第一个数字(-16
),则默认为1(1-16
);如果你省略了最后一个数字(5-
),则默认到行尾。
有用的选项
-d
C
使用字符 C
作为 -f
选项之间的 输入 分隔符,默认为制表符。--output-delimiter=
C
使用字符 C
作为 -f
选项之间的 输出 分隔符,默认为制表符。-s
抑制(不打印)不包含分隔符的行。
paste
stdin stdout - 文件 -- 选项 --help --version
paste [选项] [文件]
paste
命令与cut
命令恰好相反:它将多个文件视为垂直列并在标准输出中合并它们:
→ cat letters
A
B
C
→ cat numbers
1
2
3
4
5
→ paste numbers letters
1 A
2 B
3 C
4
5
→ paste letters numbers
A 1
B 2
C 3
4
5
有用的选项
-d
delimiters
在列之间使用给定的 delimiters
字符;默认为制表符。提供一个字符(-d:
)总是使用,或者一个字符列表(-dxyz
)在每一行上按顺序应用(第一个分隔符是x,然后是y,然后是z,然后是x,然后是y,...)。-s
横向:转置输出的行和列: → **
paste -s letters numbers** A B C 1 2 3 4 5
tr
stdin stdout - 文件 -- 选项 --help --version
tr [选项] charset1 [charset2]
tr
命令执行一些简单的、有用的字符集转换。例如,要把文件中的所有内容大写:
→ cat wonderfulfile
This is a very wonderful file.
→ cat wonderfulfile | tr 'a-z' 'A-Z'
THIS IS A VERY WONDERFUL FILE.
或者把所有元音改为星号:
→ cat wonderfulfile | tr aeiouAEIOU '*'
Th*s *s * v*ry w*nd*rf*l f*l*.
或者删除所有元音:
→ cat wonderfulfile | tr -d aeiouAEIOU
Ths s vry wndrfl fl.
作为一个实际的例子,从DOS文本文件中删除所有回车符,使其与grep
等Linux文本工具更兼容:
→ tr -d '\r' < dosfile. > linuxfile.
tr
将 charset1
中的第一个字符转换为 charset2
中的第一个字符,第二个转换为第二个,第三个转换为第三个,依此类推。如果 charset1
的长度为 *N
*,则只使用 charset2
中的前 N
个字符。(如果 charset1
比 charset2
长,请参阅 -t
选项。)
字符集可以有以下形式:
形式 含义 ABDG
字符A、B、D、G的序列。 A-Z
从A到Z的字符范围。 [x*y]
字符 x
的 y
重复。[:
class
:]
同 grep
接受的字符类([:alnum:]
、[:digit:]
等)。
tr
还理解printf
接受的转义字符“\a”(^G
= 响铃警告),“\b”(^H
= 退格),“\f”(^L
= 换页),“\n”(^J
= 新行),“\r”(^M
= 返回),“\t”(^I
= 制表符),以及“\v”(^K
= 垂直制表符),以及符号*nnn
*表示八进制值为 nnn
的字符。
tr
适用于快速简单的翻译,但对于更强大的任务,请考虑使用sed
、awk
或perl
。
有用的选项
-d
从输入中删除 charset1
中的字符。-s
从输入中删除 charset1
中找到的相邻重复项。例如,tr -s aeiouAEIOU
会将相邻的重复元音压缩为单个元音(reeeeeeally 会变成 really)。-c
补码:对 charset1
中未找到的所有字符进行操作。-t
如果 charset1
比 charset2
长,通过截短 charset1
使它们长度相同。如果没有 -t
,则 charset2
的最后一个字符(看不见的)会重复,直到 charset2
与 charset1
的长度相同。
expand
stdin stdout - file -- opt --help --version
expand [options] [files]
unexpand [options] [files]
expand(展开)
命令将制表符转换为看起来等效的空格字符数量,unexpand(取消展开)
则执行相反的操作。默认情况下,每八个空格处就有一个制表位,但你可以通过选项更改这个设置。这两个程序默认都写入标准输出。
→ expand tabfile > spacefile
→ expand spacefile > tabfile
要检查文件中是否包含空格或制表符,使用 cat -T
命令,它将制表符显示为 ^I
,或者 od -c
命令,它将制表符显示为 \t
。
Useful options
-t
N
指定每 N
个空格就有一个制表位。
sort
stdin stdout - file -- opt --help --version
sort [options] [files]
sort(排序)
命令按照字母顺序或者你指定的其他规则打印文本行。所有提供的文件都被连接起来,然后对结果进行排序并打印:
→ cat threeletters
def
xyz
abc
→ sort threeletters
abc
def
xyz
Useful options
-f
忽略大小写排序。 -n
数字排序(例如,9在10之前),而不是字母排序(10在9之前,因为它以“1”开头)。 -g
另一种数字排序方法,使用不同的算法,该算法在其他方面认识到科学记数法(7.4e3表示“7.4乘以10的三次方”,即7400)。运行 info sort
以获取完整的技术细节。-u
唯一排序:忽略重复行。(如果与 -c
一起用于检查已排序的文件,如果有任何连续的行是相同的,就会失败。)-c
不排序,只检查输入是否已经排序。如果是,什么也不打印;否则,打印一个错误消息。 -b
忽略行的开头空格。 -r
反转输出:从大到小排序。 -t
X
将 X
用作 -k
选项的字段分隔符。-k
key
选择排序键。(与 -t
结合使用,选择键之间的分隔符字符。)
排序键表示在排序时要考虑的行的一部分,而不是整行。一个例子可能是每行的第五个字符。通常,sort
会认为这些行是排序的:
aaaaz
bbbby
但是如果你的排序键是“每行的第五个字符”,表示为 -k1.5
,那么行会被反转,因为 y
在 z
之前。更实用的例子包括这个包含姓名和地址的文件:
→ cat people
George Washington,123 Main Street,New York
Abraham Lincoln,54 First Avenue,San Francisco
John Adams,39 Tremont Street,Boston
一个普通的排序会首先显示“Abraham Lincoln”这行。但是如果你把每行看作三个逗号分隔的值,你可以用以下命令按第二个值进行排序:
→ sort -k2 -t, people
George Washington,123 Main Street,New York
John Adams,39 Tremont Street,Boston
Abraham Lincoln,54 First Avenue,San Francisco
其中,“123 Main Street”在字母上是第一位。同样,你可以按城市(第三个值)进行排序:
→ sort -k3 -t, people
John Adams,39 Tremont Street,Boston
George Washington,123 Main Street,New York
Abraham Lincoln,54 First Avenue,San Francisco
项目 意义 默认值 F1
起始字段 必须提供 C1
起始字段1内的起始位置 1 F2
结束字段 最后一个字段 C2
结束字段内的起始位置 1
因此,sort -k1.5
基于第一个字段进行排序,从第五个字符开始;而sort -k2.8,5
意味着“从第二个字段的第八个字符开始,到第五个字段的第一个字符结束。”-t
选项改变了-k
的行为,所以它会考虑到像逗号这样的分隔符字符,而不是空格。
你可以重复-k
选项来定义多个键,这些键将按照命令行中找到的顺序从第一个到最后一个应用。
uniq
stdin stdout - file -- opt --help --version
uniq [options] [files]
uniq
(唯一)命令对文本的连续重复行进行操作。例如,如果你有一个文件 myfile:
→ cat letters2
a
b
b
c
b
那么uniq
会检测并处理两个连续的b,但不会处理第三个b:
→ uniq letters2
a
b
c
b
uniq
经常在对文件进行排序后使用:
→ sort letters2 | uniq
a
b
c
在这种情况下,只剩下一个b,因为所有三个b都通过sort
变成了相邻的,然后通过uniq
压缩成一个。另外,你也可以统计重复行的数量,而不是消除它们:
→ sort letters2 | uniq -c
1 a
3 b
1 c
有用的选项
-c
计数相邻重复行。 -i
大小写不敏感的操作。 -u
只打印唯一的行。 -d
只打印重复的行。 -s
N
在检测重复时,跳过每行的前* N
*个字符。-f
N
在检测重复时,忽略每行前* N
*个以空格分隔的字段。-w
N
在检测重复时,只考虑每行的前* N
个字符。如果与-s
或-f
一起使用,sort
将首先忽略指定数量的字符或字段,然后考虑接下来的N
*个字符。
tee
stdin stdout - file -- opt --help --version
tee [options] files
像cat
命令一样,tee
(茶)命令将标准输入复制到标准输出,不进行任何更改。同时,它也将相同的标准输入复制到一个或多个文件。tee
通常出现在管道的中间,将一些中间数据写入文件,同时也将其传递给管道中的下一个命令:
→ who | tee original_who | sort
barrett pts/1 Sep 22 21:15
byrnes pts/0 Sep 15 13:51
silver :0 Sep 23 20:44
silver pts/2 Sep 22 21:18
这个命令行在屏幕上产生who
的排序输出,但同时也将who
的原始,未排序的输出写入到文件 original_who:
→ cat original_who
silver :0 Sep 23 20:44
byrnes pts/0 Sep 15 13:51
barrett pts/1 Sep 22 21:15
silver pts/2 Sep 22 21:18
然后将同样的输出传递到管道的其余部分(sort
),在屏幕上产生排序的输出。
有用的选项
-a
附加,而不是覆盖文件。 -i
忽略中断信号。
更强大的操作
我们仅仅接触了Linux文本过滤的冰山一角。Linux拥有数百种过滤器,能够实现对数据的更复杂的处理。但是,强大的功能往往意味着陡峭的学习曲线,这对于一篇文章来说太多了。以下是一些可以帮助你入门的过滤器。
awk
AWK是一种基于模式匹配的语言。它通过正则表达式匹配数据,然后根据数据执行操作。以下是一些处理文本文件myfile的简单示例。
打印每行的第二个和第四个单词:
→ awk '{print $2, $4}' myfile
打印所有字符数少于60个的行:
→ awk 'length < 60 {print}' myfile
sed
就像AWK一样,sed也是一个模式匹配引擎,可以对文本行进行操作。它的语法与vim和行编辑器ed密切相关。以下是一些简单的示例。
打印文件,将所有出现的字符串“me”更改为“YOU”:
→ sed 's/me/YOU/g' myfile
打印文件,去掉前10行:
→ sed '1,10d' myfile
m4
m4是一种宏处理语言和命令。它在文件中查找关键字,并为它们替换值。例如,给定此文件:
→ cat substitutions
My name is NAME and I am AGE years old.
ifelse(QUOTE,yes,Learn Linux today!)
看看m4如何对NAME
,AGE
和QUOTE
进行替换:
→ m4 -DNAME=Sandy substitutions
My name is Sandy and I am AGE years old.
→ m4 -DNAME=Sandy -DAGE=25 substitutions
My name is Sandy and I am 25 years old.
→ m4 -DNAME=Sandy -DAGE=25 -DQUOTE=yes substitutions
My name is Sandy and I am 25 years old.
Learn Linux today!
发表评论 取消回复