Linux常用的文本处理命令

1. echo

基本用法: echo string

显示命令执行结果: echodate``

原样输出字符串,不进行转义或取变量(用单引号): echo '$name\\"'

启用转义符:echo -e "OK! \\c" # -e 开启转义 \\c 不换行

显示变量内容:echo "$name It is a test"

显示结果定向至文件:echo "It is a test" > myfile > 覆盖 >>追加

2. sort

sort 用于文本的行排序。默认排序方式是升序,按每行的字典序排序。

一些基本用法:

  • r 降序(从大到小)排序
  • u 去除重复行
  • o [file] 指定输出文件
  • n 用于数值排序,否则“15”会排在“2”前

3. uniq

uniq 也可以用来排除重复的行,但是仅对连续的重复行生效。

通常会和 sort 一起使用:

1
$ sort animals | uniq

只是去重排序明明可以用 sort -u ,uniq 工具是否多余了呢?实际上 uniq 还有其他用途。

uniq -d 可以用于仅输出重复行:

1
$ sort animals | uniq -d

uniq -c 可以用于统计各行重复次数:

1
$ sort animals | uniq -c

4. grep

grep 全称 Global Regular Expression Print,是一个强大的文本搜索工具,可以在一个或多个文件中搜索指定 pattern 并显示相关行。

grep 默认使用 BRE,要使用 ERE 可以使用 grep -E 或 egrep。

命令格式:grep [option] pattern file

一些用法:

  • n:显示匹配到内容的行号
  • v:显示不被匹配到的行
  • i:忽略字符大小写
  • o: 只返回匹配内容
1
2
3
4
$ ls /bin | grep -n "^man$"  # 搜索内容仅含 man 的行,并且显示行号
$ ls /bin | grep -v "[a-z]\\|[0-9]" # 搜索不含小写字母和数字的行
$ ls /bin | grep -iv "[A-Z]\\|[0-9]" # 搜索不含字母和数字的行
$ ifconfig | grep -oE "[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}" # 只返回ip

5. sed

sed 全称 Stream EDitor,即流编辑器,可以方便地对文件的内容进行逐行处理。

sed 默认使用 BRE,要使用 ERE 可以 sed -E

命令格式:

1
2
$ sed [OPTIONS] 'command' file(s)
$ sed [OPTIONS] -f scriptfile file(s)

此处的 command 和 scriptfile 中的命令均指的是 sed 命令。

常见 sed 命令:

  • s 替换
  • d 删除
  • c 选定行改成新文本
  • a 当前行下插入文本
  • i 当前行上插入文本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ echo -e "seD\\nIS\\ngOod" > sed_demo
$ cat sed_demo
seD
IS
gOod
$ sed "2d" sed_demo # 删除第二行
seD
gOod
$ sed "s/[a-z]/~/g" sed_demo # 替换所有小写字母为 ~
~~D
IS
~O~~
$ sed "3cpErfeCt" sed_demo # 选定第三行,改成 pErfeCt
seD
IS
pErfeCt

5. awk

awk 是一种用于处理文本的编程语言工具,名字来源于三个作者的首字母。相比 sed,awk 可以在逐行处理的基础上,针对列进行处理。默认的列分隔符号是空格,其他分隔符可以自行指定。

awk 使用 ERE。

命令格式:awk [options] 'pattern {action}' [file]

awk 逐行处理文本,对符合的 patthern 执行 action。需要注意的是,awk 使用单引号时可以直接用 $,使用双引号则要用 \\$

一些示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
docker rmi $(docker images | grep "none" | awk '{print $3}')

$ cat awk_demo
Beth 4.00 0
Dan 3.75 0
kathy 4.00 10
Mark 5.00 20
Mary 5.50 22
Susie 4.25 18
$ # 选择第三列值大于 0 的行,对每一行输出第一列的值和第二第三列的乘积
$ awk '$3 >0 { print $1, $2 * $3 }' awk_demo
kathy 40
Mark 100
Mary 121
Susie 76.5

示例中 $1$2$3 分别指代本行的第 1、2、3 列。特别地,$0 指代本行。

awk 语言是「图灵完全」的,这意味着理论上它可以做到和其他语言一样的事情。这里我们不仅可以对每行进行操作,还可以定义变量,将前面处理的状态保存下来,以下是一个求和的例子:

1
2
$ awk 'BEGIN { sum = 0 } { sum += $2 * $3 } END { print sum }' awk_demo
337.5

6. *2>&1的含义*

关于输入/输出重定向本文就不细说了,不懂的可以参考这里:Shell:管道与重定向

  • 含义:将标准错误输出重定向到标准输出
  • 符号>&是一个整体,不可分开,分开后就不是上述含义了。
    • 比如有些人可能会这么想:2是标准错误输入,1是标准输出,>是重定向符号,那么”将标准错误输出重定向到标准输出”是不是就应该写成”2>1”就行了?是这样吗?
    • 如果是尝试过,你就知道2>1的写法其实是将标准错误输出重定向到名为”1”的文件里去了
  • 写成2&>1也是不可以的

为什么2>&1要放在后面

考虑如下一条shell命令

1
nohup java -jar app.jar >log 2>&1 &

(最后一个&表示把条命令放到后台执行,不是本文重点,不懂的可以自行Google)

为什么2>&1一定要写到>log后面,才表示标准错误输出和标准输出都定向到log中?

我们不妨把1和2都理解是一个指针,然后来看上面的语句就是这样的:

1
2
3
本来1----->屏幕 (1指向屏幕)
执行>log后, 1----->log (1指向log)
执行2>&1后, 2----->1 (2指向1,而1指向log,因此2也指向了log)

每次都写”>log 2>&1”太麻烦,能简写吗?

有以下两种简写方式

1
2
&>log
>&log

比如上面小节中的写法就可以简写为:

1
nohup java -jar app.jar &>log &

上面两种方式都和”>log 2>&1”一个语义。

那么 上面两种方式中&>和>&有区别吗?

语义上是没有任何区别的,但是第一中方式是最佳选择,一般使用第一种。