流编辑sed和正则表达式替换

sed 会根据脚本命令来处理文本文件中的数据,这些命令要么从命令行中输入,要么存储在一个文本文件中,此命令执行数据的顺序如下:

  • 每次仅读取一行内容;
  • 根据提供的规则命令匹配并修改数据。注意,sed 默认不会直接修改源文件数据,而是会将数据复制到缓冲区中,修改也仅限于缓冲区中的数据;
  • 将执行结果输出。

当一行数据匹配完成后,它会继续读取下一行数据,并重复这个过程,直到将文件中所有数据处理完毕。

sed全名叫stream editor,流编辑器,用程序的方式来编辑文本,相当的hacker啊。sed基本上就是玩正则模式匹配,所以,玩sed的人,正则表达式一般都比较强。

sed 默认读取整个文件并对其中的每一行进行修改。说白了就是一行一行的操作。

sed 是一种在线编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有 改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

sed命令常用选项及含义

选项 含义
-e 脚本命令 该选项会将其后跟的脚本命令添加到已有的命令中。
-f 脚本命令文件 ,该选项会将其后文件中的脚本命令添加到已有的命令中。
-n 使用安静silent模式。在一般sed的用法中,所有来自stdin的内容一般都会被列出到屏幕上。但如果加上-n参数后,则只有经过sed特殊处理的那一行(或者动作)才会被列出来
-i 直接修改读取的文件内容,而不是由屏幕输出
-r 让sed命令支持扩展的正则表达式(默认是基础正则表达式)

sed命令常见用法

1
2
3
sed '命令' 文件名列表
sed –e '命令1' –e '命令2' –e '命令3' 文件名列表
sed -f 命令文件 文件名列表

成功使用 sed 命令的关键在于掌握各式各样的脚本命令及格式,它能帮你定制编辑文件的规则。

sed -i:直接修改文件内容

sed 的-i选项可以直接修改文件内容,这功能非常有帮助!举例来说,如果你有一个 100 万行的文件,你要在第 100 行加某些文字,此时使用 vim 可能会疯掉!因为文件太大了!那怎办?就利用 sed 啊!透过 sed 直接修改/取代的功能,你甚至不需要使用 vim 去修订!

删除空行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b


this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed '/^$/d' sed_append.txt
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# cat sed_append.txt
this is line a
this is line b


this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]#

删除空行并且替换原文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b


this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed -i '/^$/d' sed_append.txt
[root@localhost sed]# cat sed_append.txt
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]#

删除#号开头的行到最后一行之间的所有行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed '/^#/,$d' sed_append.txt
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed -i '/^#/,$d' sed_append.txt
[root@localhost sed]# cat sed_append.txt
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]#

sed脚本命令

sed脚本命令s:替换行中的部分内容

此命令的基本格式为:

1
[address]s/pattern/replacement/flags

其中,
address表示指定要操作的具体行,
pattern 指的是需要替换的内容,
replacement 指的是要替换的新内容。

此命令中常用的 flags 标记如下表所示

sed的s命令的flags标记及功能

flags标记 功能
n 1~512 之间的数字,表示指定要替换的字符串出现第几次时才进行替换,例如,一行中有 3 个 A,但用户只想替换第二个 A,这是就用到这个标记;
g 对数据中所有匹配到的内容进行替换,如果没有 g,则只会在第一次匹配成功时做替换操作。例如,一行数据中有 3 个 A,则只会替换第一个 A;
p 会打印与替换命令中指定的模式匹配的行。此标记通常与 -n 选项一起使用。
w file 将缓冲区中的内容写到指定的 file 文件中;
& 用正则表达式匹配的内容进行替换;
\n 匹配第 n 个子串,该子串之前在 pattern 中用 () 指定。
\ 转义(转义替换部分包含:&、\ 等)。

在行首添加内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed 's/^/#/g' sed_append.txt
#this is line a
#this is line b
#this is line c
#this is line d
## helloworld_1
## helloworld_2
## helloworld_3
[root@localhost sed]#

在行尾添加内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed 's/$/。/g' sed_append.txt
this is line a。
this is line b。
this is line c。
this is line d。
# helloworld_1。
# helloworld_2。
# helloworld_3。
[root@localhost sed]#

替换所有行中第n次模式匹配的地方:sed ‘s/pattern/replacement/n’

1
sed 's/pattern/replacement/n'

例如,将所有行中出现的第二个制表符\t替换为减号-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost sed]# cat SedTest.java 
public class SedTest{
public static void main(String[] args){
System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]# sed 's/\t/----/2' SedTest.java
public class SedTest{
public static void main(String[] args){
----System.out.println("HelloWorld!");
----System.out.println("sed命令示例");
----System.out.println("sed替换示例");
----for(int i=0;i<5;i++){
---- System.out.println("sed_sed_sed_sed"+i);
----}
}
}
[root@localhost sed]#

将所有行中出现的第3个sed字符串替换为全大写的SED字符串:

[root@localhost sed]# cat SedTest.java 
public class SedTest{
    public static void main(String[] args){
        System.out.println("HelloWorld!");
        System.out.println("sed命令示例");
        System.out.println("sed替换示例");
        for(int i=0;i<5;i++){
            System.out.println("sed_sed_sed_sed"+i);
        }
    }
}
[root@localhost sed]# sed 's/sed/SED/3' SedTest.java 
public class SedTest{
    public static void main(String[] args){
        System.out.println("HelloWorld!");
        System.out.println("sed命令示例");
        System.out.println("sed替换示例");
        for(int i=0;i<5;i++){
            System.out.println("sed_sed_SED_sed"+i);
        }
    }
}
[root@localhost sed]# 

替换某行中全部模式匹配的地方:sed ‘行号s/pattern/replacement/g’

把第3行中的所有\t全部替换为4个减号:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost sed]# cat -n SedTest.java 
1 public class SedTest{
2 public static void main(String[] args){
3 System.out.println("HelloWorld!");
4 System.out.println("sed命令示例");
5 System.out.println("sed替换示例");
6 for(int i=0;i<5;i++){
7 System.out.println("sed_sed_sed_sed"+i);
8 }
9 }
10 }
[root@localhost sed]# sed '3s/\t/----/g' SedTest.java|cat -n
1 public class SedTest{
2 public static void main(String[] args){
3 --------System.out.println("HelloWorld!");
4 System.out.println("sed命令示例");
5 System.out.println("sed替换示例");
6 for(int i=0;i<5;i++){
7 System.out.println("sed_sed_sed_sed"+i);
8 }
9 }
10 }
[root@localhost sed]#

替换第N行到第M行中第x次模式匹配的地方:sed ‘N,Ms/pattern/replacement/x’

1
sed 'N,Ms/pattern/replacement/x'

这里的行号范围包括N,但不包括M,也就是替换[N,M)区间内的行数。

第2到第3行之间的第2个制表符替换成四个减号

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost sed]# sed '2,3s/\t/----/2' SedTest.java 
public class SedTest{
public static void main(String[] args){
----System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]#

第2到第4行之间的第2个制表符替换成四个减号

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost sed]# sed '2,4s/\t/----/2' SedTest.java 
public class SedTest{
public static void main(String[] args){
----System.out.println("HelloWorld!");
----System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]#

替换行中所有模式匹配的地方:sed ‘s/pattern/replacement/g’

将所有行中的所有制表符全部替换为四个减号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost sed]# cat SedTest.java 
public class SedTest{
public static void main(String[] args){
System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]# sed 's/\t/----/g' SedTest.java
public class SedTest{
----public static void main(String[] args){
--------System.out.println("HelloWorld!");
--------System.out.println("sed命令示例");
--------System.out.println("sed替换示例");
--------for(int i=0;i<5;i++){
------------System.out.println("sed_sed_sed_sed"+i);
--------}
----}
}
[root@localhost sed]#

将所有的全小写的sed字符全部替换为全大写的SED字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost sed]# cat SedTest.java 
public class SedTest{
public static void main(String[] args){
System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]# sed 's/sed/SED/g' SedTest.java
public class SedTest{
public static void main(String[] args){
System.out.println("HelloWorld!");
System.out.println("SED命令示例");
System.out.println("SED替换示例");
for(int i=0;i<5;i++){
System.out.println("SED_SED_SED_SED"+i);
}
}
}
[root@localhost sed]#

将包括第1行到不包括第3行之间的制表符改成4个减号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@localhost sed]# cat SedTest.java 
public class SedTest{
public static void main(String[] args){
System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]# sed '1,3s/\t/----/g' SedTest.java
public class SedTest{
----public static void main(String[] args){
--------System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]#

将缓冲区中的内容输出到文件中:sed ‘s/pattern/replacement/flag w file’:

经过替换的行会保存在缓冲区中,没经过替换的行则不会放入缓冲区中。如果想把这些经过替换之后的行输出到文件中,可以在s脚本的后面追加flags标记w 文件名

例如,将[2,4)区间范围的行的所有\t替换成四个减号,并且输出缓冲区的内容到文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@localhost sed]# cat SedTest.java 
public class SedTest{
public static void main(String[] args){
System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]# sed '2,4s/\t/----/g w out.txt' SedTest.java
public class SedTest{
----public static void main(String[] args){
--------System.out.println("HelloWorld!");
--------System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]# ls
out.txt SedTest.java
[root@localhost sed]# cat out.txt
----public static void main(String[] args){
--------System.out.println("HelloWorld!");
--------System.out.println("sed命令示例");
[root@localhost sed]#

sed脚本命令d:删除某行

1
sed '[address]d'

如果需要删除文本中的特定行,可以用 d 脚本命令,它会删除指定行中的所有内容。但使用该命令时要特别小心,如果你忘记指定具体行的话,文件中的所有内容都会被删除,举个例子:

sed删除所有的行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost sed]# cat SedTest.java 
public class SedTest{
public static void main(String[] args){
System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]# sed 'd' SedTest.java > sed_d_out.txt
[root@localhost sed]# cat sed_d_out.txt
[root@localhost sed]#

sed删除指定行

只删除某行

1
sed '行号d'

例如,只删除第2行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost sed]# cat -n SedTest.java 
1 public class SedTest{
2 public static void main(String[] args){
3 System.out.println("HelloWorld!");
4 System.out.println("sed命令示例");
5 System.out.println("sed替换示例");
6 for(int i=0;i<5;i++){
7 System.out.println("sed_sed_sed_sed"+i);
8 }
9 }
10 }
[root@localhost sed]# sed '2d' SedTest.java
public class SedTest{
System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]#

删除第N行到第M行

1
sed '[N,M]d'

与替换不同的时,删除使用的是全闭区间。
命令sed '1,2d' SedTest.java表示删除区间[1,2]的所有行,也就是删除第1行,并且删除第2行。
而命令sed '1,2s/\t/----/g' SetTest.java,表示把区间[1,2)之间的所有行中的\t全部替换成四个减号,也就是只替换第1行,不替换第2行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@localhost sed]# cat -n SedTest.java 
1 public class SedTest{
2 public static void main(String[] args){
3 System.out.println("HelloWorld!");
4 System.out.println("sed命令示例");
5 System.out.println("sed替换示例");
6 for(int i=0;i<5;i++){
7 System.out.println("sed_sed_sed_sed"+i);
8 }
9 }
10 }
[root@localhost sed]# sed '1,2d' SedTest.java
System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]# sed '1,2s/\t/----/g' SedTest.java
public class SedTest{
----public static void main(String[] args){
System.out.println("HelloWorld!");
System.out.println("sed命令示例");
System.out.println("sed替换示例");
for(int i=0;i<5;i++){
System.out.println("sed_sed_sed_sed"+i);
}
}
}
[root@localhost sed]#

删除空行

1
sed '/^$/d' a.txt       #删除所有空行
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b


this is line c
this is line d
[root@localhost sed]# sed '/^$/d' sed_append.txt
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]#

删除#开头的行,到最后一行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b


this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed '/^#/,$d' sed_append.txt
this is line a
this is line b


this is line c
this is line d
[root@localhost sed]#

sed脚本命令a:在指定行后追加新行

在第N行之后附加新的内容

1
sed '行号a 附加的内容'

在某行之后追加一行

例如,在第2行只有追加一行字符串this is the newly inserted line

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost sed]# cat -n sed_append.txt 
1 this is line a
2 this is line b
3 this is line c
4 this is line d
[root@localhost sed]# sed '2a this is the newly inserted line' sed_append.txt |cat -n
1 this is line a
2 this is line b
3 this is the newly inserted line
4 this is line c
5 this is line d
[root@localhost sed]#

在某行之后追加多行

使用折行符号

使用在单引号中使用折行符\可以追加多行到指定行的后面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost sed]# cat -n sed_append.txt 
1 this is line a
2 this is line b
3 this is line c
4 this is line d
[root@localhost sed]# sed '2a this is the newly inserted line 1\
this is the newly inserted line 2' sed_append.txt |cat -n
1 this is line a
2 this is line b
3 this is the newly inserted line 1
4 this is the newly inserted line 2
5 this is line c
6 this is line d
[root@localhost sed]#

使用换行符\n

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost sed]# cat -n sed_append.txt 
1 this is line a
2 this is line b
3 this is line c
4 this is line d
5 helloworld1
6 helloworld2
[root@localhost sed]# sed '1i this is the newly inserted line 1\nthis is the newly inserted line 2' sed_append.txt |cat -n
1 this is the newly inserted line 1
2 this is the newly inserted line 2
3 this is line a
4 this is line b
5 this is line c
6 this is line d
7 helloworld1
8 helloworld2
[root@localhost sed]#

sed脚本命令i:在指定行之前插入新行

在第N行之前插入一行

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost sed]# cat -n sed_append.txt 
1 this is line a
2 this is line b
3 this is line c
4 this is line d
[root@localhost sed]# sed '2i this is the newly inserted line' sed_append.txt |cat -n
1 this is line a
2 this is the newly inserted line
3 this is line b
4 this is line c
5 this is line d
[root@localhost sed]#

在第N行之前插入多行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost sed]# cat -n sed_append.txt 
1 this is line a
2 this is line b
3 this is line c
4 this is line d
[root@localhost sed]# sed '2i this is the newly inserted line 1\
this is the newly inserted line 2' sed_append.txt |cat -n
1 this is line a
2 this is the newly inserted line 1
3 this is the newly inserted line 2
4 this is line b
5 this is line c
6 this is line d
[root@localhost sed]#

sed脚本命令c:替换整行

1
[address]c\用于替换的新文本

替换第2行的内容

1
2
3
4
5
6
7
8
9
10
11
[root@localhost sed]# cat -n sed_append.txt 
1 this is line a
2 this is line b
3 this is line c
4 this is line d
[root@localhost sed]# sed '2c this is the line after replacement' sed_append.txt |cat -n
1 this is line a
2 this is the line after replacement
3 this is line c
4 this is line d
[root@localhost sed]#

sed脚本命令y:字符集映射替换

y 转换命令是唯一可以处理单个字符的 sed 脚本命令,其基本格式如下:

1
sed '[address]y/inchars/outchars/'

转换命令会对 inchars 和 outchars 值进行一对一的映射,即 inchars 中的第一个字符会被转换为 outchars 中的第一个字符,第二个字符会被转换成 outchars 中的第二个字符…这个映射过程会一直持续到处理完指定字符。如果 inchars 和 outchars 的长度不同,则 sed 会产生一条错误消息。

示例1

例如按如下映射进行替换:

匹配字符 替换字符
a 1
b 2
c 3
d 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed 'y/abcd/1234/' sed_append.txt
this is line 1
this is line 2
this is line 3
this is line 4
[root@localhost sed]# sed '1,2y/abcd/1234/' sed_append.txt
this is line 1
this is line 2
this is line c
this is line d
[root@localhost sed]#

可以看到,inchars 模式中指定字符的每个实例都会被替换成 outchars 模式中相同位置的那个字符。

示例2

匹配字符 替换字符
a 1
b 2
c 3
d 4
e 5
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed '1,2y/abcde/12345/' sed_append.txt
this is lin5 1
this is lin5 2
this is line c
this is line d
[root@localhost sed]#

大小写转换

1
2
3
4
5
6
7
8
9
10
11
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed '1,2y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' sed_append.txt
THIS IS LINE A
THIS IS LINE B
this is line c
this is line d
[root@localhost sed]#

sed脚本命令p:打印某行

sed 默认会打印出被处理的输入内容,这些内容跟原始输入内容不一定完全一样,sed 的一些命令可以修改或删除输入内容,再把新的内容打印出来。
打印的输出结果并不是只对应匹配特定模式的行。
那些没有被处理的行,会原样打印。
如果只想打印匹配特定模式的行,要用 -n 选项和 p 命令。

注意:-n 选项并不表示打印匹配特定模式且被处理的行。
例如,使用 -n 选项和 d 命令不会看到任何打印,并不会打印出被删除的行。

sed -n∶使用安静(silent)模式。在一般 sed 的用法中,所有来自STDIN的资料一般都会被列出到萤幕上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来

sed ‘[address]p’ 输出匹配的行

p命令表示搜索符号条件的行,并输出该行的内容。

[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed '/^#/p' sed_append.txt 
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_1
# helloworld_2
# helloworld_2
# helloworld_3
# helloworld_3
[root@localhost sed]#

可以看到匹配的行输出了两次,第一次的输出是sed的输出,第2个输出则是脚本命令p的输出。
如果想只输出匹配的行,其他的行不输出的话,则可以加上-n参数。:

[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed -n '/^#/p' sed_append.txt 
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# 

通常 p 会与参数 sed -n 一起运作。此命令的基本格式为:

sed -n ‘[address]p’

1
sed -n '[address]p'
1
2
3
4
sed -n '1p' filename           #显示第一行 
sed -n '$p' filename #显示最后一行
sed -n '1,2p' filename #显示第一行到第二行
sed -n '2,$p' filename #显示第二行到最后一行

p 命令常见的用法是打印包含匹配文本模式的行,例如:

打印第一行

1
2
3
4
5
6
7
8
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed -n '1p' sed_append.txt
this is line a
[root@localhost sed]#

打印最后一行

1
2
3
4
5
6
7
8
9
10
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
helloworld1
helloworld2
[root@localhost sed]# sed -n '$p' sed_append.txt
helloworld2
[root@localhost sed]#

打印第1行到第2行

1
2
3
4
[root@localhost sed]# sed -n '1,2p' sed_append.txt 
this is line a
this is line b
[root@localhost sed]#

打印第2行到最后一行

1
2
3
4
5
6
7
[root@localhost sed]# sed -n '2,$p' sed_append.txt
this is line b
this is line c
this is line d
helloworld1
helloworld2
[root@localhost sed]#

打印包含指定关键字的行

1
2
3
4
5
6
7
8
9
10
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
helloworld1
helloworld2
[root@localhost sed]# sed -n '/helloworld/p' sed_append.txt
helloworld1
helloworld2

打印匹配正则表达式的行

1
2
3
4
5
6
7
8
9
10
11
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
helloworld1
helloworld2
[root@localhost sed]# sed -n '/world[0-9]/p' sed_append.txt
helloworld1
helloworld2
[root@localhost sed]#

sed -n选项p命令:只打印包含匹配模式的行

可以看到,用 -n 选项和 p 命令配合使用,可以只打印匹配的行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed -n '2p' sed_append.txt
this is line b
[root@localhost sed]# sed -n '/b/p' sed_append.txt
this is line b
[root@localhost sed]# sed -n '/line/p' sed_append.txt
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]#

sed多脚本

1
2
3
address {
多个脚本命令
}

sed显示匹配的行,并显示替换后的结果。

如果需要在修改之前查看行,也可以使用打印命令,比如与替换或修改命令一起使用。可以创建一个脚本在修改行之前显示该行,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed -n '/b/{
> p;
> s/line/row/p
> }' sed_append.txt
this is line b
this is row b
[root@localhost sed]#

sed 命令会查找包含小写字母b的行,然后执行两条命令。
首先,脚本用 p 命令来打印出原始行;
然后它用s命令替换文本,并用 p 标记打印出替换结果。
这样可以输出当前要处理的文本,以及替换之后的文本,以便于对比替换的结果是否达到要求

多个脚本命令写在一行

可以吧多个命令写在一行之中,命令之间用英文的分号;分隔开即可:

1
sed '[address]{命令1;命令2;...命令n}'
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed -n '/^#/,${p;s/helloworld/HELLOWORLD/pg}' sed_append.txt 
# helloworld_1
# HELLOWORLD_1
# helloworld_2
# HELLOWORLD_2
# helloworld_3
# HELLOWORLD_3
[root@localhost sed]# 

正则表达式词首词尾

\<表示词首。 如:\<abc表示以abc为首的詞。
\>表示词尾。 如:abc\>表示以abc結尾的詞。

打印有hello为词首的单词的行

[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# sed -n '/\<hello/p' sed_append.txt 
# helloworld_1
# helloworld_2
# helloworld_3
[root@localhost sed]# 

打印有line为词尾的单词的行

[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
&#35; helloworld_1
&#35; helloworld_2
&#35; helloworld_3
[root@localhost sed]# sed -n '/line\>/p' sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# 

sed脚本命令w file:输出模式空间中的内容到文件

w命令用来将文本中指定行的内容写入文件中,此命令的基本格式如下:

1
sed '[address]w filename'

这里的 filename 表示文件名,可以使用相对路径或绝对路径,但不管是哪种,运行 sed 命令的用户都必须有文件的写权限。
下面的例子是将数据流中的前两行打印到一个文本文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed '1,2 w sed_w_out.txt' sed_append.txt
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# cat sed_w_out.txt
this is line a
this is line b
[root@localhost sed]#

sed脚本命令r:插入独立文件的内容到当前数据流的指定位置

r 命令用于将一个独立文件的数据插入到当前数据流的指定位置,该命令的基本格式为:

1
sed "[address]r filename"

sed命令会将filename文件中的内容插入到address指定的行的后面。

在文件的某行后插入另一个文件的内容

例如,将sed_2.txt文件中的内容,插入到sed_append.txt文件中的第二行后面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# cat sed_2.txt
HelloWorld
[root@localhost sed]# sed "2r sed_2.txt" sed_append.txt
this is line a
this is line b
HelloWorld
this is line c
this is line d
[root@localhost sed]#

在文件的末尾插入另一个文件的内容

如果你想将指定文件中的数据插入到数据流的末尾,可以使用地址符$,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# cat sed_2.txt
HelloWorld
[root@localhost sed]# sed '$r sed_2.txt' sed_append.txt
this is line a
this is line b
this is line c
this is line d
HelloWorld

需要注意的是,命令如果使用的是双引号的话,则需要使用转义符,也就是双引号中的美元符号,要写成"\$",而使用单引号就不需要使用转义符,只需要写成'$'即可

1
2
3
4
5
6
7
8
9
[root@localhost sed]# sed "$r sed_2.txt" sed_append.txt 
sed:-e 表达式 #1,字符 10:未终止的“s”命令
[root@localhost sed]# sed "\$r sed_2.txt" sed_append.txt
this is line a
this is line b
this is line c
this is line d
HelloWorld
[root@localhost sed]#

sed脚本命令q:匹配第一次后就退出sed程序

q命令的作用是使sed命令在第一次匹配任务结束后,退出 sed 程序,不再进行对后续数据的处理。

sed匹配后退出

1
2
3
4
5
6
7
8
9
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed '2q' sed_append.txt
this is line a
this is line b
[root@localhost sed]#

可以看到,sed 命令在打印输出第 2 行之后,就停止了,是 q 命令造成的,再比如:

sed查找替换第一次模式匹配后退出

1
2
3
4
5
6
7
8
9
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed '/b/{ s/b/B/;q; }' sed_append.txt
this is line a
this is line B
[root@localhost sed]#

sed在当前行中查找到小写的字母b后,将小写的字母b替换成大写的字母B,然后退出sed不再处理后续的行。

sed脚本命令的寻址方式

前面在介绍各个脚本命令时,我们一直忽略了对 address 部分的介绍。对各个脚本命令来说,address 用来表明该脚本命令作用到文本中的具体行。

默认情况下,sed 命令会作用于文本数据的所有行。如果只想将命令作用于特定行或某些行,则必须写明 address 部分,表示的方法有以下 2 种:

  • 以数字形式指定行区间;
  • 用文本模式指定具体行区间。

以上两种形式都可以使用如下这 2 种格式,分别是:

1
[address]脚本命令

或者

1
2
3
4
5
6
address {
脚本命令1
脚本命令2
......
脚本命令n
}

以数字形式指定行区间

当使用数字方式的行寻址时,可以用行在文本流中的行位置来引用。sed 会将文本流中的第一行编号为 1,然后继续按顺序为接下来的行分配行号。

在脚本命令中,

  • 指定的地址可以是单个行号,
  • 也可以用起始行号+逗号+结束行号来指定指定的一定区间范围内的行(起始行号,结尾行号)。

使用数字指定行号

这里举一个 sed 命令作用到指定行号的例子:

1
2
3
4
5
6
7
8
9
10
11
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed '2s/s/_/g' sed_append.txt
this is line a
thi_ i_ line b
this is line c
this is line d
[root@localhost sed]#

可以看到,sed 只修改地址指定的第二行的文本。下面的例子中使用了行地址区间:

使用区间指定行地址

1
2
3
4
5
6
7
8
9
10
11
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed '2,3s/s/_/g' sed_append.txt
this is line a
thi_ i_ line b
thi_ i_ line c
this is line d
[root@localhost sed]#

特殊的行结束符$

在此基础上,如果想将命令作用到文本中从某行开始的所有行,可以用特殊地址——美元符($):

1
2
3
4
5
6
7
8
9
10
11
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
[root@localhost sed]# sed '2,$s/s/_/g' sed_append.txt
this is line a
thi_ i_ line b
thi_ i_ line c
thi_ i_ line d
[root@localhost sed]#

用文本模式指定行区间

sed 允许指定文本模式来过滤出命令要作用的行,格式如下:

1
/pattern/command

注意,必须用正斜线将要指定的pattern封起来,sed会将该命令作用到包含指定文本模式的行上。

固定文本模式:字符串形式的文本模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
helloworld1
helloworld2
[root@localhost sed]# cat sed_append.txt |grep 'helloworld'
helloworld1
helloworld2
[root@localhost sed]# sed '/helloworld/s/helloworld/HELLOWORLD/g' sed_append.txt
this is line a
this is line b
this is line c
this is line d
HELLOWORLD1
HELLOWORLD2
[root@localhost sed]#

虽然使用固定文本模式(字符串)能帮你过滤出特定的值,但其作用难免有限,因此,sed 允许在文本模式使用正则表达式指明作用的具体行。
正则表达式允许创建高级文本模式匹配表达式来匹配各种数据。这些表达式结合了一系列通配符、特殊字符以及固定文本字符来生成能够匹配几乎任何形式文本的简练模式。

高级文本模式:使用正则表达式的文本模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost sed]# cat sed_append.txt 
this is line a
this is line b
this is line c
this is line d
helloworld1
helloworld2
[root@localhost sed]# sed '/world[0-9]/s/world/WORLD/g' sed_append.txt
this is line a
this is line b
this is line c
this is line d
helloWORLD1
helloWORLD2
[root@localhost sed]#

sed命令帮助文档

sed –help

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
[root@localhost ~]# sed --help
用法: sed [选项]... {脚本(如果没有其他脚本)} [输入文件]...

-n, --quiet, --silent
取消自动打印模式空间
-e 脚本, --expression=脚本
添加“脚本”到程序的运行列表
-f 脚本文件, --file=脚本文件
添加“脚本文件”到程序的运行列表
--follow-symlinks
直接修改文件时跟随软链接
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if SUFFIX supplied)
-c, --copy
use copy instead of rename when shuffling files in -i mode
-b, --binary
does nothing; for compatibility with WIN32/CYGWIN/MSDOS/EMX (
open files in binary mode (CR+LFs are not treated specially))
-l N, --line-length=N
指定“l”命令的换行期望长度
--posix
关闭所有 GNU 扩展
-r, --regexp-extended
在脚本中使用扩展正则表达式
-s, --separate
将输入文件视为各个独立的文件而不是一个长的连续输入
-u, --unbuffered
从输入文件读取最少的数据,更频繁的刷新输出
-z, --null-data
separate lines by NUL characters
--help
display this help and exit
--version
output version information and exit

如果没有 -e, --expression, -f 或 --file 选项,那么第一个非选项参数被视为
sed脚本。其他非选项参数被视为输入文件,如果没有输入文件,那么程序将从标准
输入读取数据。
GNU sed home page: <http://www.gnu.org/software/sed/>.
General help using GNU software: <http://www.gnu.org/gethelp/>.
E-mail bug reports to: <bug-sed@gnu.org>.
Be sure to include the word ``sed'' somewhere in the ``Subject:'' field.
[root@localhost ~]#

man sed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
SED(1)                                                          User Commands                                                          SED(1)

NAME
sed - stream editor for filtering and transforming text

SYNOPSIS
sed [OPTION]... {script-only-if-no-other-script} [input-file]...

DESCRIPTION
Sed is a stream editor. A stream editor is used to perform basic text transformations on an input stream (a file or input from a
pipeline). While in some ways similar to an editor which permits scripted edits (such as ed), sed works by making only one pass over
the input(s), and is consequently more efficient. But it is sed's ability to filter text in a pipeline which particularly distin‐
guishes it from other types of editors.

-n, --quiet, --silent

suppress automatic printing of pattern space

-e script, --expression=script

add the script to the commands to be executed

-f script-file, --file=script-file

add the contents of script-file to the commands to be executed

--follow-symlinks

follow symlinks when processing in place

-i[SUFFIX], --in-place[=SUFFIX]

edit files in place (makes backup if SUFFIX supplied)

-c, --copy

use copy instead of rename when shuffling files in -i mode

-b, --binary

does nothing; for compatibility with WIN32/CYGWIN/MSDOS/EMX ( open files in binary mode (CR+LFs are not treated specially))

-l N, --line-length=N

specify the desired line-wrap length for the `l' command

--posix

disable all GNU extensions.

-r, --regexp-extended

use extended regular expressions in the script.

-s, --separate

consider files as separate rather than as a single continuous long stream.

-u, --unbuffered

load minimal amounts of data from the input files and flush the output buffers more often

-z, --null-data

separate lines by NUL characters

--help

display this help and exit

--version

output version information and exit

If no -e, --expression, -f, or --file option is given, then the first non-option argument is taken as the sed script to interpret.
All remaining arguments are names of input files; if no input files are specified, then the standard input is read.

GNU sed home page: <http://www.gnu.org/software/sed/>. General help using GNU software: <http://www.gnu.org/gethelp/>. E-mail bug
reports to: <bug-sed@gnu.org>. Be sure to include the word ``sed'' somewhere in the ``Subject:'' field.

COMMAND SYNOPSIS
This is just a brief synopsis of sed commands to serve as a reminder to those who already know sed; other documentation (such as the
texinfo document) must be consulted for fuller descriptions.

Zero-address ``commands''
: label
Label for b and t commands.

#comment
The comment extends until the next newline (or the end of a -e script fragment).

} The closing bracket of a { } block.

Zero- or One- address commands
= Print the current line number.

a \

text Append text, which has each embedded newline preceded by a backslash.

i \

text Insert text, which has each embedded newline preceded by a backslash.

q [exit-code]
Immediately quit the sed script without processing any more input, except that if auto-print is not disabled the current pat‐
tern space will be printed. The exit code argument is a GNU extension.

Q [exit-code]
Immediately quit the sed script without processing any more input. This is a GNU extension.

r filename
Append text read from filename.

R filename
Append a line read from filename. Each invocation of the command reads a line from the file. This is a GNU extension.

Commands which accept address ranges
{ Begin a block of commands (end with a }).

b label
Branch to label; if label is omitted, branch to end of script.

c \

text Replace the selected lines with text, which has each embedded newline preceded by a backslash.

d Delete pattern space. Start next cycle.

D If pattern space contains no newline, start a normal new cycle as if the d command was issued. Otherwise, delete text in the
pattern space up to the first newline, and restart cycle with the resultant pattern space, without reading a new line of input.

h H Copy/append pattern space to hold space.

g G Copy/append hold space to pattern space.

l List out the current line in a ``visually unambiguous'' form.

l width
List out the current line in a ``visually unambiguous'' form, breaking it at width characters. This is a GNU extension.

n N Read/append the next line of input into the pattern space.

p Print the current pattern space.

P Print up to the first embedded newline of the current pattern space.

s/regexp/replacement/
Attempt to match regexp against the pattern space. If successful, replace that portion matched with replacement. The replace‐
ment may contain the special character & to refer to that portion of the pattern space which matched, and the special escapes
\1 through \9 to refer to the corresponding matching sub-expressions in the regexp.

t label
If a s/// has done a successful substitution since the last input line was read and since the last t or T command, then branch
to label; if label is omitted, branch to end of script.

T label
If no s/// has done a successful substitution since the last input line was read and since the last t or T command, then branch
to label; if label is omitted, branch to end of script. This is a GNU extension.

w filename
Write the current pattern space to filename.

W filename
Write the first line of the current pattern space to filename. This is a GNU extension.

x Exchange the contents of the hold and pattern spaces.

y/source/dest/
Transliterate the characters in the pattern space which appear in source to the corresponding character in dest.

Addresses
Sed commands can be given with no addresses, in which case the command will be executed for all input lines; with one address, in
which case the command will only be executed for input lines which match that address; or with two addresses, in which case the com‐
mand will be executed for all input lines which match the inclusive range of lines starting from the first address and continuing to
the second address. Three things to note about address ranges: the syntax is addr1,addr2 (i.e., the addresses are separated by a
comma); the line which addr1 matched will always be accepted, even if addr2 selects an earlier line; and if addr2 is a regexp, it will
not be tested against the line that addr1 matched.

After the address (or address-range), and before the command, a ! may be inserted, which specifies that the command shall only be
executed if the address (or address-range) does not match.

The following address types are supported:

number Match only the specified line number (which increments cumulatively across files, unless the -s option is specified on the com‐
mand line).

first~step
Match every step'th line starting with line first. For example, ``sed -n 1~2p'' will print all the odd-numbered lines in the
input stream, and the address 2~5 will match every fifth line, starting with the second. first can be zero; in this case, sed
operates as if it were equal to step. (This is an extension.)

$ Match the last line.

/regexp/
Match lines matching the regular expression regexp.

\cregexpc
Match lines matching the regular expression regexp. The c may be any character.

GNU sed also supports some special 2-address forms:

0,addr2
Start out in "matched first address" state, until addr2 is found. This is similar to 1,addr2, except that if addr2 matches the
very first line of input the 0,addr2 form will be at the end of its range, whereas the 1,addr2 form will still be at the begin‐
ning of its range. This works only when addr2 is a regular expression.

addr1,+N
Will match addr1 and the N lines following addr1.

addr1,~N
Will match addr1 and the lines following addr1 until the next line whose input line number is a multiple of N.

REGULAR EXPRESSIONS
POSIX.2 BREs should be supported, but they aren't completely because of performance problems. The \n sequence in a regular expression
matches the newline character, and similarly for \a, \t, and other sequences.

BUGS
E-mail bug reports to bug-sed@gnu.org. Also, please include the output of ``sed --version'' in the body of your report if at all pos‐
sible.

AUTHOR
Written by Jay Fenlason, Tom Lord, Ken Pizzini, and Paolo Bonzini. GNU sed home page: <http://www.gnu.org/software/sed/>. General
help using GNU software: <http://www.gnu.org/gethelp/>. E-mail bug reports to: <bug-sed@gnu.org>. Be sure to include the word
``sed'' somewhere in the ``Subject:'' field.

COPYRIGHT
Copyright © 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.

SEE ALSO
awk(1), ed(1), grep(1), tr(1), perlre(1), sed.info, any of various books on sed, the sed FAQ (http://sed.sf.net/grabbag/tutorials/sed‐
faq.txt), http://sed.sf.net/grabbag/.

The full documentation for sed is maintained as a Texinfo manual. If the info and sed programs are properly installed at your site,
the command

info sed

should give you access to the complete manual.

sed 4.2.2 September 2020 SED(1)
Manual page sed(1) line 210/246 (END) (press h for help or q to quit)

参考资料

http://c.biancheng.net/view/4028.html
http://c.biancheng.net/view/4056.html
https://www.runoob.com/linux/linux-comm-sed.html
https://developer.aliyun.com/article/320516
https://www.cnblogs.com/dong008259/archive/2011/12/07/2279897.html
https://coolshell.cn/articles/9104.html
https://qianngchn.github.io/wiki/4.html

https://segmentfault.com/a/1190000022722531
https://www.linuxcool.com/sed
https://www.cnblogs.com/ggjucheng/archive/2013/01/13/2856901.html
https://learnku.com/server/wikis/36595
http://linux.51yip.com/search/sed
https://zhuanlan.zhihu.com/p/130797132

手册

http://www.gnu.org/software/sed/manual/sed.html

grep/egrep/fgrep:在文件中查找字符串(筛选)

grep在文件中查找字符串

grep(Global regular expression print)

语法

grep 模式 文件名列表

egrep 使用扩展正则表达式ERE描述模式

在指定模式方面比grep更灵活

fgrep 快速搜索指定字符串

按字符串搜索而不是按模式搜索。

grep选项

-F, –fixed-strings Fixed strings (instead of regular expressions)
-G, –basic-regexp Basic regular expression (BRE)
-E, –extended-regexp Extended regular expression (ERE)
-P, –perl-regexp Perl-compatible regular expression (PCRE)

-n 显示时每行前面显示行号
-v 显示所有不包含模式的行
-i 字母比较时忽略字母的大小写

例:grep -n main *.c
查找含有正则表达式main的行,并打印行号
当文件数超过一个时,除了输出行号,还输出文件名

例:grep -v ‘[Dd]isable’ dev.stat>dev.active
取消文件中所有含有指定模式的行,生成新文件。

例:grep -i richard telnos
在文件中检索字符串richard,不顾字母的大小写

帮助文档

PCRE语法

查PCRE语法:man pcresyntax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
PCRESYNTAX(3)                                                        Library Functions Manual                                                       PCRESYNTAX(3)

NAME
PCRE - Perl-compatible regular expressions

PCRE REGULAR EXPRESSION SYNTAX SUMMARY

The full syntax and semantics of the regular expressions that are supported by PCRE are described in the pcrepattern documentation. This document contains
a quick-reference summary of the syntax.

QUOTING

\x where x is non-alphanumeric is a literal x
\Q...\E treat enclosed characters as literal

CHARACTERS

\a alarm, that is, the BEL character (hex 07)
\cx "control-x", where x is any ASCII character
\e escape (hex 1B)
\f form feed (hex 0C)
\n newline (hex 0A)
\r carriage return (hex 0D)
\t tab (hex 09)
\ddd character with octal code ddd, or backreference
\xhh character with hex code hh
\x{hhh..} character with hex code hhh..

CHARACTER TYPES

. any character except newline;
in dotall mode, any character whatsoever
\C one data unit, even in UTF mode (best avoided)
\d a decimal digit
\D a character that is not a decimal digit
\h a horizontal white space character
\H a character that is not a horizontal white space character
\N a character that is not a newline
\p{xx} a character with the xx property
\P{xx} a character without the xx property
\R a newline sequence
\s a white space character
\S a character that is not a white space character
\v a vertical white space character
\V a character that is not a vertical white space character
\w a "word" character
\W a "non-word" character
\X a Unicode extended grapheme cluster

In PCRE, by default, \d, \D, \s, \S, \w, and \W recognize only ASCII characters, even in a UTF mode. However, this can be changed by setting the PCRE_UCP
option.

GENERAL CATEGORY PROPERTIES FOR \p and \P

C Other
Cc Control
Cf Format
Cn Unassigned
Co Private use
Cs Surrogate

L Letter
Ll Lower case letter
Lm Modifier letter
Lo Other letter
Lt Title case letter
Lu Upper case letter
L& Ll, Lu, or Lt

M Mark
Mc Spacing mark
Me Enclosing mark
Mn Non-spacing mark

N Number
Nd Decimal number
Nl Letter number
No Other number

P Punctuation
Pc Connector punctuation
Pd Dash punctuation
Pe Close punctuation
Pf Final punctuation
Pi Initial punctuation
Po Other punctuation
Ps Open punctuation

S Symbol
Sc Currency symbol
Sk Modifier symbol
Sm Mathematical symbol
So Other symbol

Z Separator
Zl Line separator
Zp Paragraph separator
Zs Space separator

PCRE SPECIAL CATEGORY PROPERTIES FOR \p and \P

Xan Alphanumeric: union of properties L and N
Xps POSIX space: property Z or tab, NL, VT, FF, CR
Xsp Perl space: property Z or tab, NL, FF, CR
Xwd Perl word: property Xan or underscore

SCRIPT NAMES FOR \p AND \P

Arabic, Armenian, Avestan, Balinese, Bamum, Batak, Bengali, Bopomofo, Brahmi, Braille, Buginese, Buhid, Canadian_Aboriginal, Carian, Chakma, Cham, Chero‐
kee, Common, Coptic, Cuneiform, Cypriot, Cyrillic, Deseret, Devanagari, Egyptian_Hieroglyphs, Ethiopic, Georgian, Glagolitic, Gothic, Greek, Gujarati,
Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana, Imperial_Aramaic, Inherited, Inscriptional_Pahlavi, Inscriptional_Parthian, Javanese, Kaithi, Kannada,
Katakana, Kayah_Li, Kharoshthi, Khmer, Lao, Latin, Lepcha, Limbu, Linear_B, Lisu, Lycian, Lydian, Malayalam, Mandaic, Meetei_Mayek, Meroitic_Cursive,
Meroitic_Hieroglyphs, Miao, Mongolian, Myanmar, New_Tai_Lue, Nko, Ogham, Old_Italic, Old_Persian, Old_South_Arabian, Old_Turkic, Ol_Chiki, Oriya, Osmanya,
Phags_Pa, Phoenician, Rejang, Runic, Samaritan, Saurashtra, Sharada, Shavian, Sinhala, Sora_Sompeng, Sundanese, Syloti_Nagri, Syriac, Tagalog, Tagbanwa,
Tai_Le, Tai_Tham, Tai_Viet, Takri, Tamil, Telugu, Thaana, Thai, Tibetan, Tifinagh, Ugaritic, Vai, Yi.

CHARACTER CLASSES

[...] positive character class
[^...] negative character class
[x-y] range (can be used for hex characters)
[[:xxx:]] positive POSIX named set
[[:^xxx:]] negative POSIX named set

alnum alphanumeric
alpha alphabetic
ascii 0-127
blank space or tab
cntrl control character
digit decimal digit
graph printing, excluding space
lower lower case letter
print printing, including space
punct printing, excluding alphanumeric
space white space
upper upper case letter
word same as \w
xdigit hexadecimal digit

In PCRE, POSIX character set names recognize only ASCII characters by default, but some of them use Unicode properties if PCRE_UCP is set. You can use
\Q...\E inside a character class.

QUANTIFIERS

? 0 or 1, greedy
?+ 0 or 1, possessive
?? 0 or 1, lazy
* 0 or more, greedy
*+ 0 or more, possessive
*? 0 or more, lazy
+ 1 or more, greedy
++ 1 or more, possessive
+? 1 or more, lazy
{n} exactly n
{n,m} at least n, no more than m, greedy
{n,m}+ at least n, no more than m, possessive
{n,m}? at least n, no more than m, lazy
{n,} n or more, greedy
{n,}+ n or more, possessive
{n,}? n or more, lazy

ANCHORS AND SIMPLE ASSERTIONS

\b word boundary
\B not a word boundary
^ start of subject
also after internal newline in multiline mode
\A start of subject
$ end of subject
also before newline at end of subject
also before internal newline in multiline mode
\Z end of subject
also before newline at end of subject
\z end of subject
\G first matching position in subject

MATCH POINT RESET

\K reset start of match

ALTERNATION

expr|expr|expr...

CAPTURING

(...) capturing group
(?<name>...) named capturing group (Perl)
(?'name'...) named capturing group (Perl)
(?P<name>...) named capturing group (Python)
(?:...) non-capturing group
(?|...) non-capturing group; reset group numbers for
capturing groups in each alternative

ATOMIC GROUPS

(?>...) atomic, non-capturing group

COMMENT

(?#....) comment (not nestable)

OPTION SETTING

(?i) caseless
(?J) allow duplicate names
(?m) multiline
(?s) single line (dotall)
(?U) default ungreedy (lazy)
(?x) extended (ignore white space)
(?-...) unset option(s)

The following are recognized only at the start of a pattern or after one of the newline-setting options with similar syntax:

(*NO_START_OPT) no start-match optimization (PCRE_NO_START_OPTIMIZE)
(*UTF8) set UTF-8 mode: 8-bit library (PCRE_UTF8)
(*UTF16) set UTF-16 mode: 16-bit library (PCRE_UTF16)
(*UTF32) set UTF-32 mode: 32-bit library (PCRE_UTF32)
(*UTF) set appropriate UTF mode for the library in use
(*UCP) set PCRE_UCP (use Unicode properties for \d etc)

LOOKAHEAD AND LOOKBEHIND ASSERTIONS

(?=...) positive look ahead
(?!...) negative look ahead
(?<=...) positive look behind
(?<!...) negative look behind

Each top-level branch of a look behind must be of a fixed length.

BACKREFERENCES

\n reference by number (can be ambiguous)
\gn reference by number
\g{n} reference by number
\g{-n} relative reference by number
\k<name> reference by name (Perl)
\k'name' reference by name (Perl)
\g{name} reference by name (Perl)
\k{name} reference by name (.NET)
(?P=name) reference by name (Python)

SUBROUTINE REFERENCES (POSSIBLY RECURSIVE)

(?R) recurse whole pattern
(?n) call subpattern by absolute number
(?+n) call subpattern by relative number
(?-n) call subpattern by relative number
(?&name) call subpattern by name (Perl)
(?P>name) call subpattern by name (Python)
\g<name> call subpattern by name (Oniguruma)
\g'name' call subpattern by name (Oniguruma)
\g<n> call subpattern by absolute number (Oniguruma)
\g'n' call subpattern by absolute number (Oniguruma)
\g<+n> call subpattern by relative number (PCRE extension)
\g'+n' call subpattern by relative number (PCRE extension)
\g<-n> call subpattern by relative number (PCRE extension)
\g'-n' call subpattern by relative number (PCRE extension)

CONDITIONAL PATTERNS

(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)

(?(n)... absolute reference condition
(?(+n)... relative reference condition
(?(-n)... relative reference condition
(?(<name>)... named reference condition (Perl)
(?('name')... named reference condition (Perl)
(?(name)... named reference condition (PCRE)
(?(R)... overall recursion condition
(?(Rn)... specific group recursion condition
(?(R&name)... specific recursion condition
(?(DEFINE)... define subpattern for reference
(?(assert)... assertion condition

BACKTRACKING CONTROL

The following act immediately they are reached:

(*ACCEPT) force successful match
(*FAIL) force backtrack; synonym (*F)
(*MARK:NAME) set name to be passed back; synonym (*:NAME)

The following act only when a subsequent match failure causes a backtrack to reach them. They all force a match failure, but they differ in what happens
afterwards. Those that advance the start-of-match point do so only if the pattern is not anchored.

(*COMMIT) overall failure, no advance of starting point
(*PRUNE) advance to next starting character
(*PRUNE:NAME) equivalent to (*MARK:NAME)(*PRUNE)
(*SKIP) advance to current matching position
(*SKIP:NAME) advance to position corresponding to an earlier
(*MARK:NAME); if not found, the (*SKIP) is ignored
(*THEN) local failure, backtrack to next alternation
(*THEN:NAME) equivalent to (*MARK:NAME)(*THEN)

NEWLINE CONVENTIONS

These are recognized only at the very start of the pattern or after a (*BSR_...), (*UTF8), (*UTF16), (*UTF32) or (*UCP) option.

(*CR) carriage return only
(*LF) linefeed only
(*CRLF) carriage return followed by linefeed
(*ANYCRLF) all three of the above
(*ANY) any Unicode newline sequence

WHAT \R MATCHES

These are recognized only at the very start of the pattern or after a (*...) option that sets the newline convention or a UTF or UCP mode.

(*BSR_ANYCRLF) CR, LF, or CRLF
(*BSR_UNICODE) any Unicode newline sequence

CALLOUTS

(?C) callout
(?Cn) callout with data n

SEE ALSO

pcrepattern(3), pcreapi(3), pcrecallout(3), pcrematching(3), pcre(3).

AUTHOR

Philip Hazel
University Computing Service
Cambridge CB2 3QH, England.

REVISION

Last updated: 11 November 2012
Copyright (c) 1997-2012 University of Cambridge.

PCRE 8.32 11 November 2012 PCRESYNTAX(3)

man grep

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
NAME
grep, egrep, fgrep - 打印匹配给定模式的行

总览 SYNOPSIS
grep [options] PATTERN [FILE...]
grep [options] [-e PATTERN | -f FILE] [FILE...]

描述 DESCRIPTION
Grep 搜索以 FILE 命名的文件输入 (或者是标准输入,如果没有指定文件名,或者给出的文件名是 - 的话),寻找含有与给定的模式 PATTERN 相匹配的内容的行。
将把含有匹配内容的行打印出来。

另外,也可以使用两个变种程序 egrep 和 fgrep 。 Egrep 与 grep -E 相同。 Fgrep 与 grep -F 相同。

选项 OPTIONS
-A NUM, --after-context=NUM
打印出紧随匹配的行之后的下文 NUM 行。在相邻的匹配组之间将会打印内容是 -- 的一行。

-a, --text
将一个二进制文件视为一个文本文件来处理;它与 --binary-files=text 选项等价。

-B NUM, --before-context=NUM
打印出匹配的行之前的上文 NUM 行。在相邻的匹配组之间将会打印内容是 -- 的一行。

-C NUM, --context=NUM
打印出匹配的行的上下文前后各 NUM 行。在相邻的匹配组之间将会打印内容是 -- 的一行。

-b, --byte-offset
在输出的每行前面同时打印出当前行在输入文件中的字节偏移量。

--binary-files=TYPE
如果一个文件的起始几个字节表明文件包含二进制数据,那么假定文件是 TYPE 类型的。默认情况下, TYPE 是 binary ,
一般会输出一个一行的消息说一个二进制文件匹配,或者如果没有匹配的话就没有消息输出。如果类型 TYPE 是 without-match ,那么 grep 假定二进制文件不会
选项等价。如果类型 TYPE 是 text ,那么 grep 将一个二进制文件视为文本文件来处理;它与 -a 选项等价。 警告: grep -
可能会输出二进制的无用内容。如果输出设备是一个终端,并且终端的驱动将这些输出中的一些当作命令,可能会带来恶劣的副作用。

--colour[=WHEN], --color[=WHEN]
在匹配的行周围以 GREP_COLOR 环境变量中指定的记号来标记。WHEN 可以是 `never', `always', 或是 `auto'。

-c, --count
禁止通常的输出;作为替代,为每一个输入文件打印一个匹配的行的总数。如果使用 -v, --invert-match 选项 (参见下面),将是不匹配的行的总数。

-D ACTION, --devices=ACTION
如果输入文件是一个设备,FIFO 或是套接字 (socket) ,使用动作 ACTION 来处理它。默认情况下,动作 ACTION 是 read ,意味着设备将视为普通文件那样来读。如果动
,将不处理而直接跳过设备。

-d ACTION, --directories=ACTION
如果输入文件是一个目录,使用动作 ACTION 来处理它。默认情况下,动作 ACTION 是 read ,意味着目录将视为普通文件那样来读。如果动作 ACTI
,将不处理而直接跳过目录。如果动作 ACTION 是 recurse , grep 将递归地读每一目录下的所有文件。这样做和 -r 选项等价。

-E, --extended-regexp
将模式 PATTERN 作为一个扩展的正则表达式来解释 (参见下面)。

-e PATTERN, --regexp=PATTERN
使用模式 PATTERN 作为模式;在保护以 - 为起始的模式时有用。

-F, --fixed-strings
将模式 PATTERN 视为一个固定的字符串的列表,用新行 (newlines) 分隔,只要匹配其中之一即可。

-P, --perl-regexp
将模式 PATTERN 作为一个 Perl 正则表达式来解释。

-f FILE, --file=FILE
从文件 FILE 中获取模式,每行一个。空文件含有0个模式,因此不匹配任何东西。

-G, --basic-regexp
将模式 PATTERN 作为一个基本的正则表达式 (参见下面) 来解释。这是默认值。

-H, --with-filename
为每个匹配打印文件名。

-h, --no-filename
当搜索多个文件时,禁止在输出的前面加上文件名前缀。

--help 输出一个简短的帮助信息。

-I 处理一个二进制文件,但是认为它不包含匹配的内容。这和 --binary-files=without-match 选项等价。

-i, --ignore-case
忽略模式 PATTERN 和输入文件中的大小写的分别。

-L, --files-without-match
禁止通常的输出;作为替代,打印出每个在通常情况下不会产生输出的输入文件的名字。对每个文件的扫描在遇到第一个匹配的时候就会停止。

-l, --files-with-matches
禁止通常的输出;作为替代,打印出每个在通常情况下会产生输出的输入文件的名字。对每个文件的扫描在遇到第一个匹配的时候就会停止。

-m NUM, --max-count=NUM
在找到 NUM 个匹配的行之后,不再读这个文件。如果输入是来自一个普通文件的标准输入,并且已经输出了 NUM 个匹配的行
保证标准输入被定位于退出时的最后一次匹配的行之后,不管是否指定了要输出紧随的下文的行。这样可以使一个调用程序恢复搜索。当 grep 在
个匹配的行之后停止,它会输出任何紧随的下文的行。当使用了 -c 或 --count 选项的时候, grep 不会输出比 NUM 更多的行。当指定了 -v 或 --invert-match 选项的时
NUM 个不匹配的行之后停止。

--mmap 如果可能的话,使用 mmap(2) 系统调用来读取输入,而不是默认的 read(2) 系统调用。在一些情况下, --mmap 提供较好的性能。但是,如果一个输
正在操作时大小发生变化,或者如果发生了一个 I/O 错误, --mmap 可能导致不可知的行为 (包括core dumps)。

-n, --line-number
在输出的每行前面加上它所在的文件中它的行号。

-o, --only-matching
只显示匹配的行中与 PATTERN 相匹配的部分。

--label=LABEL
将实际上来自标准输入的输入视为来自输入文件 LABEL 。这对于 zgrep 这样的工具非常有用,例如: gzip -cd foo.gz |grep --label=foo something

--line-buffering
使用行缓冲,it can be a performance penality.

-q, --quiet, --silent
安静。不向标准输出写任何东西。如果找到任何匹配的内容就立即以状态值 0 退出,即使检测到了错误。 参见 -s 或 --no-messages 选项。

-R, -r, --recursive
递归地读每一目录下的所有文件。这样做和 -d recurse 选项等价。

--include=PATTERN
仅仅在搜索匹配 PATTERN 的文件时在目录中递归搜索。

--exclude=PATTERN
在目录中递归搜索,但是跳过匹配 PATTERN 的文件。

-s, --no-messages
禁止输出关于文件不存在或不可读的错误信息。 对于可移植性需要注意:与 GNU grep 不同,传统的 grep 不遵守 POSIX.2 规范,因为传统的 grep 缺少一个 -q 选项,而
grep 的 -q 选项行为相似。需要可移植到传统 grep 的 shell 脚本应当避免使用 -q 和 -s 选项,而应当将输出重定向到 /dev/null 。

-U, --binary
将文件视为二进制。默认情况下,在 MS-DOS 和 MS-Windows 系统中, grep 通过从文件中读取头部的 32kB 内容来判断它的文件类
判断文件是一个文本文件,它将原始文件内容中的 CR 字符去除 (使得含有 ^ 和 $ 的正则表达式可以正常工作
将不进行这些工作,而使所有文件保持不变地读取并传递给匹配机制。如果文件是一个以 CR/LF 换行的文本文件,这样作将导致一些正则表达式失败。这个选项在 MS-DOS
之外的系统中无效。

-u, --unix-byte-offsets
报告 Unix 风格的字节偏移量。这个开关使得 grep 报告字节偏移量时,将文件作为 Unix 风格的文本文件看待,也就是说将 CR 字符去掉。这将产生与在一台 Uni
完全相同的结果。除非同时使用 -b 选项,否则这个选项无效。这个选项在 MS-DOS 和 MS-Windows 之外的系统中无效。

-V, --version
向标准错误输出打印 grep 的版本号。版本号应当包含在所有的 bug 报告中 (参见下面)。

-v, --invert-match
改变匹配的意义,只选择不匹配的行。

-w, --word-regexp
只选择含有能组成完整的词的匹配的行。判断方法是匹配的子字符串必须是一行的开始,或者是在一个不可能是词的组成的字符之后。与此相似,它必须是一行的结束,或者是
的字符之前。词的组成字符是字母,数字,还有下划线。

-x, --line-regexp
只选择能匹配完整一行的匹配。

-y -i 的同义词,废弃不用。

-Z, --null
输出一个全零字节 (ASCII 码中的 NUL 字符) 而不是一般情况下输出在文件名之后的字符。例如,
在每个文件名之后输出一个全零字节而不是普通的新行符。这个选项使得输出清楚明白,即使文件名的表示中包含特殊字符比如新行符。这个选项可以与命令 find -print0,
和 xargs -0 一起使用,来处理任意的文件名,即使是那些含有新行符的文件名。

正则表达式 REGULAR EXPRESSIONS
一个正则表达式是一个描述了一个字符串集合的模式。正则表达式的构造类似于算术表达式,使用各种各样的操作符来将更小的表达式连在一起。

Grep 能理解两种不同版本的正则表达式语法:“basic” 和 “extended”。在 GNU grep 中,两种语法可以实现的功能是没有区别的。在其他实现中,
正则表达式表达能力要弱一点。下面的描述适用于扩展的 (extended) 正则表达式,它与基本正则表达式的区别会在最后做一个总结。

基本的构造块是匹配单个字符的正则表达式。大部分字符,包括所有字母和数字,是匹配它们自身的正则表达式。任何具有特殊含义的元字符可以通过前置一个反斜杠来引用。(may b
ceding it with a backslash.)

方括号表达式 (bracket) 是一个字符序列,放在 [ 和 ] 当中。它匹配序列中的任何一个字符;如果序列中的第一个字符是脱字符 (caret) ^
序列中的任何一个字符。例如,正则表达式 [0123456789] 匹配任何一个数字。

在方括号表达式之中,一个 范围表达式 (range) 由两个字符组成,中间用一个连字符 (hyphen) 分隔。它匹配在这两个字符之间的任何一个字符,使用本地化的序列顺序和字符
between the two characters,inclusive, using the locale's collating sequence and character set.) 例如,在默认的 C locale中, [a-d] 与 [abcd] 等价。典
将字符以字典顺序排序,在这些 locale 中, [a-d] 不与 [abcd] 等价;例如它可能与 [aBbCcDd] 等价。要获得传统的对方括号表达式的解释,可以设定环境变量 LC_ALL 值为 C 来

最后,在方括号表达式中有一些预定义的字符类,如下所示。它们的名字是自说明的,它们是 [:alnum:](字母和数字), [:alpha:](字母), [:cntrl:](), [:digit:](数字
[:lower:](小写字母), [:print:](可打印字符), [:punct:](), [:space:](空格), [:upper:](大写字母), 和 [:xdigit:] 。例如, [[:alnum:]] 意思是 [0-9A-Za-z] ,但是后
locale C 和ASCII 字符编码,而前一种是与 locale 和字符集无关的。(注意这些字符类名中的方括号也是符号名称的一部分,必须包含在用来为序列定界的方括号之中。)

大多数元字符处于序列中时会失去它们的特殊意义。为了包含一个字面意义 (literal) 的 ] ,需要将它放在序列的最前。与此相似,为了包含一个字面意义 (lit
,需要将它放在除了序列最前之外的其他位置。最后,为了包含一个字面意义 (literal) 的 - ,需要将它放在序列最后。

句点符 (period) . 匹配任何一个字符。符号 \w 是 [[:alnum:]] 的同义词, \W 是 [^[:alnum]] 的同义词。

脱字符 (caret) ^ 和美元标记 (dollar) $ 分别是匹配一行的首部和尾部的空字串的元字符。符号 \< 和 \> 分别是匹配一个词的首部和尾部的空字串的元字符。符号 \b 匹配
的空字串,符号 \B 匹配 不 处于一个词的边缘的空字串。

一个正则表达式后面可以跟随多种重复操作符之一。
? 先前的项是可选的,最多匹配一次。
* 先前的项可以匹配零次或多次。
+ 先前的项可以匹配一次或多次。
{n} 先前的项将匹配恰好 n 次。
{n,} 先前的项可以匹配 n 或更多次。
{n,m} 先前的项将匹配至少 n 词,但是不会超过 m 次。

两个正则表达式可以连接到一起;得出的正则表达式可以匹配任何由两个分别匹配连接前的子表达式的子字符串连接而成的字符串。

两个正则表达式可以用中缀操作符 | 联合到一起,得出的正则表达式可以匹配任何匹配联合前的任何一个子表达式的字符串。

重复操作符的优先级比连接高,接下来又比选择的优先级高。一个完整的子表达式可以用圆括号 (parentheses) 括住来超越这些优先级规则。(to override these precedence rules

反向引用 \n 中, n 是一个数字,匹配正则表达式中,以第 n 个圆括号括住的子表达式已匹配的子字符串。

在基本正则表达式中,元字符 ?, +, {, |, (, 和 ) 丧失了它们的特殊意义;作为替代,使用加反斜杠的 (backslash) 版本 \?, \+, \{, \|, \(, 和 \) 。

传统的 egrep 不支持元字符 { ,并且一些 egrep 的实现通过支持 \{ 来代替它,因此可移植的脚本应当避免 在 egrep 中使用 { 模式,应当使用 [{] 来匹配一个字面意义 (liter

GNU egrep 通过假设如果 { 处于 an invalid interval specification 的起始,就不是一个特殊字符,来支持传统的用法。例如,shell 命令 egrep '{1' 将会搜索这个
而不是报告在正则表达式中发生了语法错误。POSIX.2 允许这个行为,将其视为一个扩展,但是可移植的脚本应当避免使用它。

环境变量 ENVIRONMENT VARIABLES
Grep 的行为受下列环境变量影响。

一个 locale LC_foo 是通过按下面的顺序, LC_ALL, LC_foo, LANG, 检查这三个环境变量的取值而确定的。设置了的第一个变量指定了 locale。例如,如果 LC_ALL 没有设置
设置为 pt_BR ,那么巴西的葡萄牙语 (Brazilian Portuguese) 将用作 LC_MESSAGES locale 的值。如果没有设置这其中任何一个环境变量,或者没有安装所设置的 locale 目
没有将国家和语言支持 (national language support (NLS)) 编译在内,将默认使用 locale C。

GREP_OPTIONS
这个变量指定了将放在所有显式指定的选项之前的默认选项。例如,如果 GREP_OPTIONS 是 '--binary-files=without-match --directories=skip'
将像已经在任何显式指定的选项之前指定了 --binary-files=without-match 和 --directories=skip 选项那样来运作。选项以空白 (whitespace) 分隔。一个反
使得下一个字符转义 (escape),因此可以用来指定一个含有空白或者反斜杠的选项。

GREP_COLOR
指定用来高亮显示的标记。

LC_ALL, LC_COLLATE, LANG
这些变量指定了 locale LC_COLLATE ,决定了解释类似 [a-z] 的范围表达式时的序列顺序 (collating sequence) 。

LC_ALL, LC_CTYPE, LANG
这些选项指定了 locale LC_CTYPE ,决定了字符的类型,例如,哪些字符是空白 (whitespace) 。

LC_ALL, LC_MESSAGES, LANG
这些选项指定了 locale LC_MESSAGES ,决定了 grep 的消息使用的语言。默认的 locale C 使用美国英语的消息。

POSIXLY_CORRECT
如果设置了的话, grep 将像 POSIX.2 要求的那样来运作;否则, grep 将像其他 GNU 程序一样来运作。POSIX.2
要求文件名之后的选项必须视为文件名;默认情况下,这些选项被交换到操作数列表的前面,被当作选项来处理。同时, POSIX.2 要求不可识别的选项在诊断消息
中表示为 “ille?
gal”,但是既然它们没有真正触犯法律,因此默认情况下它们在诊断 (diagnose) 消息中表示为 “invalid”。 POSIXLY_CORRECT 同时禁止了下面描述的 _N_GNU_nonoption_argv_flags_。

_N_GNU_nonoption_argv_flags_
(这里 N 是 grep's 数字形式的进程ID。) 如果这个环境变量的值的第 i 个字符是 1 ,那么不将 grep 的第 i 个操作数视为一个选项,即使它看上去像。shell
可以将这个变量设置在它运行的每个命令的环境中,指定哪个操作数是文件名通配符扩展的结果,因此不应当被视为选项。这个行为只有在使用 GNU C 库时有效,并且只有在 POSIXLY_CORRECT
没有设置的时候。

诊断 DIAGNOSTICS
一般地,如果找到了选择的行,退出时状态值为0,否则为1。但是如果发生错误,退出时状态值是2,除非指定了 -q 或 --quiet 或 --silent 选项,并且找到了选择的行。

BUGS
bug 报告的电子邮件地址是 bug-gnu-utils@gnu.org。 一定要在“Subject:”中带有 “grep” 这个词。

在 {n,m} 结构中重复次数过多会导致 grep 使用大量内存。另外,一些过分晦涩的正则表达式需要指数级的时间和空间,可能会导致 grep 耗尽所有内存。

向后引用 (backreferences) 非常慢,可能需要指数级的时间。

grep –help

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
[root@localhost ~]# grep --help
用法: grep [选项]... PATTERN [FILE]...
在每个 FILE 或是标准输入中查找 PATTERN。
默认的 PATTERN 是一个基本正则表达式(缩写为 BRE)。
例如: grep -i 'hello world' menu.h main.c

正则表达式选择与解释:
-E, --extended-regexp PATTERN 是一个可扩展的正则表达式(缩写为 ERE)
-F, --fixed-strings PATTERN 是一组由断行符分隔的定长字符串。
-G, --basic-regexp PATTERN 是一个基本正则表达式(缩写为 BRE)
-P, --perl-regexp PATTERN 是一个 Perl 正则表达式
-e, --regexp=PATTERN 用 PATTERN 来进行匹配操作
-f, --file=FILE 从 FILE 中取得 PATTERN
-i, --ignore-case 忽略大小写
-w, --word-regexp 强制 PATTERN 仅完全匹配字词
-x, --line-regexp 强制 PATTERN 仅完全匹配一行
-z, --null-data 一个 0 字节的数据行,但不是空行

Miscellaneous:
-s, --no-messages suppress error messages
-v, --invert-match select non-matching lines
-V, --version display version information and exit
--help display this help text and exit

输出控制:
-m, --max-count=NUM NUM 次匹配后停止
-b, --byte-offset 输出的同时打印字节偏移
-n, --line-number 输出的同时打印行号
--line-buffered 每行输出清空
-H, --with-filename 为每一匹配项打印文件名
-h, --no-filename 输出时不显示文件名前缀
--label=LABEL 将LABEL 作为标准输入文件名前缀
-o, --only-matching show only the part of a line matching PATTERN
-q, --quiet, --silent suppress all normal output
--binary-files=TYPE assume that binary files are TYPE;
TYPE is 'binary', 'text', or 'without-match'
-a, --text equivalent to --binary-files=text
-I equivalent to --binary-files=without-match
-d, --directories=ACTION how to handle directories;
ACTION is 'read', 'recurse', or 'skip'
-D, --devices=ACTION how to handle devices, FIFOs and sockets;
ACTION is 'read' or 'skip'
-r, --recursive like --directories=recurse
-R, --dereference-recursive
likewise, but follow all symlinks
--include=FILE_PATTERN
search only files that match FILE_PATTERN
--exclude=FILE_PATTERN
skip files and directories matching FILE_PATTERN
--exclude-from=FILE skip files matching any file pattern from FILE
--exclude-dir=PATTERN directories that match PATTERN will be skipped.
-L, --files-without-match print only names of FILEs containing no match
-l, --files-with-matches print only names of FILEs containing matches
-c, --count print only a count of matching lines per FILE
-T, --initial-tab make tabs line up (if needed)
-Z, --null print 0 byte after FILE name

文件控制:
-B, --before-context=NUM 打印以文本起始的NUM 行
-A, --after-context=NUM 打印以文本结尾的NUM 行
-C, --context=NUM 打印输出文本NUM 行
-NUM same as --context=NUM
--group-separator=SEP use SEP as a group separator
--no-group-separator use empty string as a group separator
--color[=WHEN],
--colour[=WHEN] use markers to highlight the matching strings;
WHEN is 'always', 'never', or 'auto'
-U, --binary do not strip CR characters at EOL (MSDOS/Windows)
-u, --unix-byte-offsets report offsets as if CRs were not there
(MSDOS/Windows)

‘egrep’即‘grep -E’。‘fgrep’即‘grep -F’。
直接使用‘egrep’或是‘fgrep’均已不可行了。
若FILE 为 -,将读取标准输入。不带FILE,读取当前目录,除非命令行中指定了-r 选项。
如果少于两个FILE 参数,就要默认使用-h 参数。
如果有任意行被匹配,那退出状态为 0,否则为 1;
如果有错误产生,且未指定 -q 参数,那退出状态为 2。

grep命令示例

显示当前目录下的所有子目录:ls -l|grep ‘^d’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@localhost Linux_Test]# ls -l
总用量 48
-rw-r--r--. 1 root root 0 5月 3 15:27 a.txt
-rw-r--r--. 1 root root 0 5月 3 15:27 b.txt
drwxr-xr-x. 2 root root 4096 5月 1 15:16 cat
-rw-r--r--. 1 root root 0 5月 3 15:27 c.txt
drwxr-xr-x. 2 root root 4096 5月 1 15:18 date
-rw-r--r--. 1 root root 0 5月 3 15:27 d.txt
drwxr-xr-x. 2 root root 4096 5月 1 15:16 less
drwxr-xr-x. 2 root root 4096 5月 1 15:14 ls
drwxr-xr-x. 2 root root 4096 5月 1 15:15 more
drwxr-xr-x. 2 root root 4096 5月 1 15:18 ps
drwxr-xr-x. 2 root root 4096 5月 1 15:15 sort
drwxr-xr-x. 2 root root 4096 5月 1 15:14 tr
drwxr-xr-x. 2 root root 4096 5月 1 18:47 uniq
drwxr-xr-x. 2 root root 4096 5月 1 15:17 vi
drwxr-xr-x. 2 root root 4096 5月 1 15:17 wc
drwxr-xr-x. 4 root root 4096 5月 3 14:36 正则表达式
[root@localhost Linux_Test]# ls -l|grep '^d'
drwxr-xr-x. 2 root root 4096 5月 1 15:16 cat
drwxr-xr-x. 2 root root 4096 5月 1 15:18 date
drwxr-xr-x. 2 root root 4096 5月 1 15:16 less
drwxr-xr-x. 2 root root 4096 5月 1 15:14 ls
drwxr-xr-x. 2 root root 4096 5月 1 15:15 more
drwxr-xr-x. 2 root root 4096 5月 1 15:18 ps
drwxr-xr-x. 2 root root 4096 5月 1 15:15 sort
drwxr-xr-x. 2 root root 4096 5月 1 15:14 tr
drwxr-xr-x. 2 root root 4096 5月 1 18:47 uniq
drwxr-xr-x. 2 root root 4096 5月 1 15:17 vi
drwxr-xr-x. 2 root root 4096 5月 1 15:17 wc
drwxr-xr-x. 4 root root 4096 5月 3 14:36 正则表达式
[root@localhost Linux_Test]#

显示当前目录下的所有文件:ls -l|grep ‘^-‘

1
2
3
4
5
6
[root@localhost Linux_Test]# ls -l|grep '^-'
-rw-r--r--. 1 root root 0 5月 3 15:27 a.txt
-rw-r--r--. 1 root root 0 5月 3 15:27 b.txt
-rw-r--r--. 1 root root 0 5月 3 15:27 c.txt
-rw-r--r--. 1 root root 0 5月 3 15:27 d.txt
[root@localhost Linux_Test]#

参考资料

单字符正则表达式的组合

串结

abc串结在一起,可以匹配abc本身。
[A-Z].[0-9].串结在一起,可以匹配AA00

星号(*)

单字符正则表达式后跟*,表示匹配这个单字符正则表达式的0次或任意多次。
例:正则表达式12*4
与字符串1234不匹配,与1224,12224,14匹配

例:正则表达式[A-Z][0-9]*
此例中*作用的单字符正则表式为[0-9],代表

1
2
3
4
5
[A-Z]
[A-Z][0-9]
[A-Z][0-9][0-9]
[A-Z][0-9][0-9][0-9]
......

这与A,A1,C45,D768匹配,与b64512,T56t不匹配。

例:正则表达式[Cc]hapter *[1-4]
在*号前有一个空格,允许数字1-4之前有多个或者0个空格。可匹配Chapter2,chapter 3等等。
例:正则表达式a\[i] *= *b\[j] *\* *c\[k]
匹配字符串a[i]=b[j]*c[k],容许等号和星号两侧有空格

例:在vi中使用正则表达式
:1,$s/[0-9]*/xx/g1,$表示从第1行到最后一行,s/[0-9]*/_/g表示把一行的所有的数字全部替换成_
需要注意的是

1
2
3
123 123 234 123 
a b c
hello2 hello3 hello4

替换结果:

1
2
3
_ _ _ _ 
_a_ _b_ _c
_h_e_l_l_o_ _h_e_l_l_o_ _h_e_l_l_o_

需要注意的是当没有数字的时候,[0-9]*可以匹配0次,这将匹配到一个空字符串,在一行中,任何两个字符之间都认为有一个空字符串。
所以替换的结果就是在任何两个字符之间添加一个_字符。这可能不是我们所希望的,在使用的时候应该多注意星号*匹配0次的情况。

锚点:$与^

锚点表示要匹配的字符串必须处于的位置。

$在尾部时有特殊意义,否则与其自身匹配

例:123$匹配文件中行尾的123,不在行尾的123字符不匹配
例:$123与字符串$123匹配
例:.$匹配行尾的任意字符

^在首部时有特殊意义,否则与其自身匹配

例:^printf匹配行首的printf字符串,不在行首的printf串不匹配
例:Hel^lo与字符串Hel^lo匹配
例:在vi中使用 :1,$s/^----//g表示删除第一行到最后一行的每行行首的4个减号-

1
2
3
0123456789
----hello
--------world

替换结果:

1
2
3
0123456789
hello
----world

正则表达式扩展

ERE:扩展的正则表达式(ERE)
PCRE: Perl-compatible regular expression

对基本正则表达式(BRE)进行了改进:

  • 添加分组:圆括号() :
    • (xy)*可匹配空字符串,xyxyxyxyxyxy
  • 添加逻辑运算:表示逻辑“或” 的符号 |
    • (pink|green)表示与pink或green匹配
  • 复次数定义:与星号地位类似的+和?,限定重复次数 {m,n}
    • *号表示它左边的单字符正则表达式重复的0次或多次
    • +号表示重复1次或多次:
      • [0-9]+:匹配长度至少为1数字串
    • ?表示0次或一次:
      • a?:匹配零个或一个a
    • 限定重复次数\{m,n\},例如:
      • [1-9][0-9]\{6,8\}:7-9位数字,首位非0
  • 命名的预定义集合
    • [[:xdigit:]]:十六进制数字
    • \d:数字
    • \D:非数字
  • ^$更灵活的锚点定义
    • 例如:寻找一个数字串,但是要求这个数字串不许出现在“合计”两个字之后

正则表达式的概念

正则表达式Regular Expressions应用范围

字符串匹配操作和替换操作
举例:Linux中的vi more grep yacc lex awk sed
其他:Visual Studio,Word等文本编辑器

正则表达式的功能

描述一个字符串模式
注意
正则表达式规则与文件名通配符规则不同

  • 正则表达式规则用于文本处理的场合
  • 文件名匹配规则用于文件处理的场合

不同软件对正则表达式的定义会有差异

正则表达式的特殊字符(元字符)

6个元字符

.*[\^$
所谓的元字符,就是一些控制字符,这些有特殊的含义。

转义

用反斜线可以取消特殊字符的特殊含义。
如:正则表达end\.只与字符串end.匹配

单字符正则表达式

长的正则表达式由单字符正则表达式构成的
非特殊字符与其自身匹配
如:正则表达式a与字符串a匹配, b与b,/与/

转义字符(\)

\.\*\$\^\[\\
正则表达式\*与字符串*匹配,与字符串\*不匹配。

转义字符后除以上六种之外的不该出现其他字符,例如:不该出现\u,这样的组合被视为undefined(未定义的),后出的软件有可能会有特殊的解释

圆点

圆点.:匹配任意单字符

定义集合

基本用法

  • 在一对方括号之间的字符为集合的内容,
    • 如:单字符正则表达式[abcd]与a或b,c,d匹配
  • 圆点,星号,反斜线在方括号内时,代表它们自己
    • 如:[\*.]可匹配\*.这3个单字符本身。

用减号-定义一个区间

[a-d][A-Z][a-zA-Z0-9]
[][] 集合含左右中括号两个字符

减号在最后,则失去表示区间的意义
[ad-]只与ad-3个字符匹配。

用^表示补集

^在集合的开头,则表示与集合内字符之外的任意字符匹配
如:[^a-z]匹配任一非小写字母
[^][]匹配任一非中括号字符
^不在集合的开头,则失去其表示补集的意义
如:[a-z^]能匹配a-z等26个字符和^字符本身,也就是一共能匹配27个单字符

Linux uniq命令:筛选文件中的重复行

Linux的uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。

uniq –help

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[root@localhost Linux_Test]# uniq --help
用法:uniq [选项]... [文件]
Filter adjacent matching lines from INPUT (or standard input),
writing to OUTPUT (or standard output).

With no options, matching lines are merged to the first occurrence.

Mandatory arguments to long options are mandatory for short options too.
-c, --count prefix lines by the number of occurrences
-d, --repeated only print duplicate lines, one for each group
-D, --all-repeated[=METHOD] print all duplicate lines
groups can be delimited with an empty line
METHOD={none(default),prepend,separate}
-f, --skip-fields=N avoid comparing the first N fields
--group[=METHOD] show all items, separating groups with an empty line
METHOD={separate(default),prepend,append,both}
-i, --ignore-case ignore differences in case when comparing
-s, --skip-chars=N avoid comparing the first N characters
-u, --unique only print unique lines
-z, --zero-terminated end lines with 0 byte, not newline
-w, --check-chars=N 对每行第N 个字符以后的内容不作对照
--help 显示此帮助信息并退出
--version 显示版本信息并退出

若域中为先空字符(通常包括空格以及制表符),然后非空字符,域中字符前的空字符将被跳过。

Note: 'uniq' does not detect repeated lines unless they are adjacent.
You may want to sort the input first, or use 'sort -u' without 'uniq'.
Also, comparisons honor the rules specified by 'LC_COLLATE'.

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
请向<http://translationproject.org/team/zh_CN.html> 报告uniq 的翻译错误
要获取完整文档,请运行:info coreutils 'uniq invocation'
[root@localhost Linux_Test]#

man uniq

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
UNIQ(1)                                                              FSF                                                              UNIQ(1)

NAME
uniq - 删除排序文件中的重复行

总览 (SYNOPSIS)
../src/uniq [OPTION]... [INPUT [OUTPUT]]

描述 (DESCRIPTION)
从 INPUT (或 标准输入) 数据 中 忽略 (但是 保留 一行) 连续的 相似行, 结果 送入 OUTPUT (或 标准输出).

-c, --count
在 行首 显示 出现 的 数目

-d, --repeated
仅显示 重复行

-D, --all-repeated
显示 全部 重复行

-f, --skip-fields=N
不比较 起初的 N 栏

-i, --ignore-case
比较时 忽略 大小写

-s, --skip-chars=N
不比较 起初的 N 个 字符

-u, --unique
仅显示 无重复行

-w, --check-chars=N
每行中 比较 不超过 N 个 字符

-N 同 -f N

+N 同 -s N

--help 显示 帮助信息, 然后 结束

--version
显示 版本信息, 然后 结束

栏(field) 指 一段 空白符(whitespace), 接下来 一段 非空白符. 字符前 的 栏 被 忽略 (Fields are skipped before chars).

uniq命令示例

uniq:删除文件中的重复行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost uniq]# cat uniq_1.txt 
1
2
3
3
3
3
4
4
4
5
5
5
8
20

使用uniq 命令删除重复行后,有如下输出结果:

1
2
3
4
5
6
7
8
9
[root@localhost uniq]# uniq uniq_1.txt 
1
2
3
4
5
8
20
[root@localhost uniq]#

uniq -c:删除文件重复行并显示重复行次数

检查文件并删除文件中重复出现的行,并在行首显示该行重复出现的次数。使用如下命令:

1
2
3
4
5
6
7
8
9
[root@localhost uniq]# uniq -c uniq_1.txt 
1 1
1 2
4 3
3 4
3 5
1 8
1 20
[root@localhost uniq]#

输出的第1列表示重复次数,第2列表示该行的内容。

uniq -d:只打印一次文件中的重复行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost uniq]# cat uniq_1.txt 
1
2
3
3
3
3
4
4
4
5
5
5
8
20
[root@localhost uniq]# uniq -d uniq_1.txt
3
4
5
[root@localhost uniq]#

uniq -D:打印文件中所有重复行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[root@localhost uniq]# cat uniq_1.txt 
1
2
3
3
3
3
4
4
4
5
5
5
8
20
[root@localhost uniq]# uniq -d uniq_1.txt
3
4
5
[root@localhost uniq]# uniq -D uniq_1.txt
3
3
3
3
4
4
4
5
5
5
[root@localhost uniq]#

uniq -f N:行比较的时候忽略前面的N个字段

例如我现在有如下的文件

1
2
3
4
5
6
7
8
[root@localhost uniq]# cat uniq_4.txt 
0 0 0 a
0 1 0 a
1 0 0 a
0 0 0 A
0 1 0 A
1 0 0 A
[root@localhost uniq]#

如果比较整行的话,所有的行都不相同:

1
2
3
4
5
6
7
8
[root@localhost uniq]# uniq uniq_4.txt 
0 0 0 a
0 1 0 a
1 0 0 a
0 0 0 A
0 1 0 A
1 0 0 A
[root@localhost uniq]#

但是,如果忽略前面两个字段的影响的话,则文件中两行:

1
2
3
4
[root@localhost uniq]# uniq -f 2 uniq_4.txt 
0 0 0 a
0 0 0 A
[root@localhost uniq]#
1
2
3
4
[root@localhost uniq]# uniq -c -f 2 uniq_4.txt 
3 0 0 0 a
3 0 0 0 A
[root@localhost uniq]#

uniq -s N:行比较时忽略行首之后的N个字符

1
2
3
4
5
6
7
8
[root@localhost uniq]# cat uniq_5.txt 
0_0_0_a
0_1_0_a
1_0_0_a
0_0_0_A
0_1_0_A
1_0_0_A
[root@localhost uniq]#

比较时忽略行首之后的4个字符:

0_0_0_a
0_1_0_a
1_0_0_a
0_0_0_A
0_1_0_A
1_0_0_A

运行结果:

[root@localhost uniq]# uniq -c -s 4 uniq_5.txt 
      3 0_0_0_a
      3 0_0_0_A
[root@localhost uniq]# 

忽略前三个字符:

0_0_0_a
0_1_0_a
1_0_0_a
0_0_0_A
0_1_0_A
1_0_0_A

运行结果:

[root@localhost uniq]# uniq -c -s 3 uniq_5.txt 
      3 0_0_0_a
      3 0_0_0_A
[root@localhost uniq]#

忽略前2个字符:

0_0_0_a
0_1_0_a
1_0_0_a
0_0_0_A
0_1_0_A
1_0_0_A

结果:

[root@localhost uniq]# uniq -c -s 2 uniq_5.txt 
      1 0_0_0_a
      1 0_1_0_a
      1 1_0_0_a
      1 0_0_0_A
      1 0_1_0_A
      1 1_0_0_A
[root@localhost uniq]# 

uniq -i:忽略大小写比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@localhost uniq]# cat uniq_3.txt 
a
A
a
b
B
b
B
c
c
c
C
[root@localhost uniq]# uniq -c uniq_3.txt
1 a
1 A
1 a
1 b
1 B
1 b
1 B
3 c
1 C
[root@localhost uniq]# uniq -ci uniq_3.txt
3 a
4 b
4 c
[root@localhost uniq]#

uniq -u:只显示没有重复的行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@localhost uniq]# cat uniq_1.txt 
1
2
3
3
3
3
4
4
4
5
5
5
8
20
[root@localhost uniq]# uniq -c uniq_1.txt
1 1
1 2
4 3
3 4
3 5
1 8
1 20
[root@localhost uniq]# uniq -uc uniq_1.txt
1 1
1 2
1 8
1 20
[root@localhost uniq]#

uniq对不相邻的重复行不起作用

当重复的行并不相邻时,uniq 命令是不起作用的,即若文件内容为以下时,uniq 命令不起作用:

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost uniq]# cat uniq_2.txt 
1
2
1
2
1
2
1
2
1
2
[root@localhost uniq]#

运行效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost uniq]# cat -n uniq_2.txt 
1 1
2 2
3 1
4 2
5 1
6 2
7 1
8 2
9 1
10 2
[root@localhost uniq]# uniq uniq_2.txt |cat -n
1 1
2 2
3 1
4 2
5 1
6 2
7 1
8 2
9 1
10 2
[root@localhost uniq]#

uniq与sort搭配使用

sort|uniq -c:统计各行在文件中出现的次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost uniq]# cat uniq_2.txt 
1
2
1
2
1
2
1
2
1
2
[root@localhost uniq]# sort uniq_2.txt |uniq -c
5 1
5 2
[root@localhost uniq]#

sort|uniq -d:在文件中找出重复的行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost uniq]# uniq uniq_2.txt 
1
2
1
2
1
2
1
2
1
2
[root@localhost uniq]# uniq -d uniq_2.txt
[root@localhost uniq]# sort uniq_2.txt|uniq -d
1
2
[root@localhost uniq]#

sort|uniq -u:在文件中找出没有重复的行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[root@localhost uniq]# cat uniq_1.txt 
1
2
3
3
3
3
4
4
4
5
5
5
8
20
[root@localhost uniq]# sort uniq_1.txt
1
2
20
3
3
3
3
4
4
4
5
5
5
8
[root@localhost uniq]# sort uniq_1.txt |uniq -u
1
2
20
8
[root@localhost uniq]#

参考资料

https://www.runoob.com/linux/linux-comm-uniq.html
https://wangchujiang.com/linux-command/c/uniq.html
https://www.linuxidc.com/Linux/2018-12/155980.htm

Linux tr命令

tr命令 可以对来自标准输入的字符进行替换、压缩和删除。它可以将一组字符变成另一组字符,经常用来编写优美的单行命令,作用很强大。
tr 是 Linux 和 Unix 系统中的命令行实用程序,用于转换,删除和挤压标准输入中的字符,并将结果写入标准输出。
该 tr 命令通常通过管道与其他命令结合使用,可以执行删除重复字符,将大写转换为小写,以及替换和删除基本字符等操作。
tr的英文全称是“ transform ”,即转换的意思。该命令

  • 可以将字符进行替换、压缩、删除,
  • 也可以将一组字符转换成另一组字符。

tr只能从标准输入中读取数据,因此,tr要么将输入文件重定向到标准输入,要么从管道读入数据。
注意:tr类似于sed命令,但是比sed简单,所以tr能实现的功能,sed都能实现。

tr命令常用参数:

tr命令参数 含义
-c 选定字符串1中字符集的补集,即反选字符串1的补集
-d 删除字符串1中出现的所有字符
-s 删除所有重复出现的字符序列,只保留一个

tr –help

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
[root@localhost Linux_Test]# tr --help
用法:tr [选项]... SET1 [SET2]
从标准输入中替换、缩减和/或删除字符,并将结果写到标准输出。

-c, -C, --complement 首先补足SET1
-d, --delete 删除匹配SET1 的内容,并不作替换
-s, --squeeze-repeats 如果匹配于SET1 的字符在输入序列中存在连续的
重复,在替换时会被统一缩为一个字符的长度
-t, --truncate-set1 先将SET1 的长度截为和SET2 相等
--help 显示此帮助信息并退出
--version 显示版本信息并退出

SET 是一组字符串,一般都可按照字面含义理解。解析序列如下:

\NNN 八进制值为NNN 的字符(1 至3 个数位)
\\ 反斜杠
\a 终端鸣响
\b 退格
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
字符1-字符2 从字符1 到字符2 的升序递增过程中经历的所有字符
[字符*] 在SET2 中适用,指定字符会被连续复制直到吻合设置1 的长度
[字符*次数] 对字符执行指定次数的复制,若次数以 0 开头则被视为八进制数
[:alnum:] 所有的字母和数字
[:alpha:] 所有的字母
[:blank:] 所有呈水平排列的空白字符
[:cntrl:] 所有的控制字符
[:digit:] 所有的数字
[:graph:] 所有的可打印字符,不包括空格
[:lower:] 所有的小写字母
[:print:] 所有的可打印字符,包括空格
[:punct:] 所有的标点字符
[:space:] 所有呈水平或垂直排列的空白字符
[:upper:] 所有的大写字母
[:xdigit:] 所有的十六进制数
[=字符=] 所有和指定字符相等的字符

仅在SET1 和SET2 都给出,同时没有-d 选项的时候才会进行替换。
仅在替换时才可能用到-t 选项。如果需要SET2 将被通过在末尾添加原来的末字符的方式
补充到同SET1 等长。SET2 中多余的字符将被省略。只有[:lower:] 和[:upper:]
以升序展开字符;在用于替换时的SET2 中以成对表示大小写转换。-s 作用于SET1,既不
替换也不删除,否则在替换或展开后使用SET2 缩减。

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
请向<http://translationproject.org/team/zh_CN.html> 报告tr 的翻译错误
要获取完整文档,请运行:info coreutils 'tr invocation'
[root@localhost Linux_Test]#s

man tr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
TR(1)                                                           User Commands                                                           TR(1)

NAME
tr - translate or delete characters

SYNOPSIS
tr [OPTION]... SET1 [SET2]

DESCRIPTION
Translate, squeeze, and/or delete characters from standard input, writing to standard output.

-c, -C, --complement
use the complement of SET1

-d, --delete
delete characters in SET1, do not translate

-s, --squeeze-repeats
replace each input sequence of a repeated character that is listed in SET1 with a single occurrence of that character

-t, --truncate-set1
first truncate SET1 to length of SET2

--help display this help and exit

--version
output version information and exit

SETs are specified as strings of characters. Most represent themselves. Interpreted sequences are:

\NNN character with octal value NNN (1 to 3 octal digits)

\\ backslash

\a audible BEL

\b backspace

\f form feed

\n new line

\r return

\t horizontal tab

\v vertical tab

CHAR1-CHAR2
all characters from CHAR1 to CHAR2 in ascending order

[CHAR*]
in SET2, copies of CHAR until length of SET1

[CHAR*REPEAT]
REPEAT copies of CHAR, REPEAT octal if starting with 0

[:alnum:]
all letters and digits

[:alpha:]
all letters

[:blank:]
all horizontal whitespace

[:cntrl:]
all control characters

[:digit:]
all digits

[:graph:]
all printable characters, not including space

[:lower:]
all lower case letters

[:print:]
all printable characters, including space

[:punct:]
all punctuation characters

[:space:]
all horizontal or vertical whitespace

[:upper:]
all upper case letters

[:xdigit:]
all hexadecimal digits

[=CHAR=]
all characters which are equivalent to CHAR

Translation occurs if -d is not given and both SET1 and SET2 appear. -t may be used only when translating. SET2 is extended to
length of SET1 by repeating its last character as necessary. Excess characters of SET2 are ignored. Only [:lower:] and [:upper:] are
guaranteed to expand in ascending order; used in SET2 while translating, they may only be used in pairs to specify case conversion.
-s uses SET1 if not translating nor deleting; else squeezing uses SET2 and occurs after translation or deletion.

GNU coreutils online help: <http://www.gnu.org/software/coreutils/> Report tr translation bugs to <http://translationpro‐
ject.org/team/>

AUTHOR
Written by Jim Meyering.

tr命令示例

映射替换

tr接受两组字符,通常具有相同的长度,并用第二组中的相应字符替换第一组的字符

1
2
3
[root@localhost Linux_Test]# echo 'aaaaa_bbbbb_cccc' | tr 'abc' 'ABC'
AAAAA_BBBBB_CCCC
[root@localhost Linux_Test]#

将a替换成A,将b替换成B,将c替换成C

使用定义字符集

tr -c SET1 SET2:不再SET1中的字符替换成SET2中的字符

[root@localhost Linux_Test]# echo 'aaaaaa_bbbbbbb_cccccc_ddddd'|tr -c 'cdef_\n' '1'
111111_1111111_cccccc_ddddd
[root@localhost Linux_Test]# echo 'aaaaaa_bbbbbbb_cccccc_ddddd'|tr -c 'cdef_' '1'
111111_1111111_cccccc_ddddd1[root@localhost Linux_Test]# 
[root@localhost Linux_Test]# 

您可能已经注意到输出比输入多了一个字符。这是因为该 echo 命令打印了一个不可见换行符 \n 也被替换为 y 。要在没有新行的情况下回显字符串,请使用该 -n 选项。

1
2
3
[root@localhost Linux_Test]# echo -n 'aaaaaa_bbbbbbb_cccccc_ddddd'|tr -c 'cdef_' '1'
111111_1111111_cccccc_ddddd[root@localhost Linux_Test]#
[root@localhost Linux_Test]#

大小写转换

1
2
3
4
5
6
7
8
9
10
11
[root@localhost Linux_Test]# cat tr.txt 
abc 012
def 345
ghi 678
jkl 909
[root@localhost Linux_Test]# tr "[a-z]" "[A-Z]" < tr.txt
ABC 012
DEF 345
GHI 678
JKL 909
[root@localhost Linux_Test]#

tr -d SET1:删除匹配SET1 的内容,并不作替换

1
2
3
4
5
6
7
8
9
10
11
[root@localhost Linux_Test]# cat tr.txt 
abc 012
def 345
ghi 678
jkl 909
[root@localhost Linux_Test]# tr -d "[a-z]" < tr.txt
012
345
678
909
[root@localhost Linux_Test]#

tr -s:压缩重复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost Linux_Test]# cat tr_1.txt 
1
2




7
8
[root@localhost Linux_Test]# tr -s "\n" <tr_1.txt
1
2
7
8
[root@localhost Linux_Test]#

tr -t SET1 SET2

默认情况下的tr SET1 SET2,如果 SET1 大于 SET2 tr 将重用 SET2 的最后一个字符。

1
2
3
4
[root@localhost Linux_Test]# echo 'aaaaaa_bbbbbbb_cccccc_ddddd'|tr 'abcd' '1234'
111111_2222222_333333_44444
[root@localhost Linux_Test]# echo 'aaaaaa_bbbbbbb_cccccc_ddddd'|tr 'abcd' '123'
111111_2222222_333333_33333

而使用-t(–truncate-set1) 选项,则会强制 tr 到做进一步处理之前截断 SET1 到 SET2 的长度。

1
2
3
[root@localhost Linux_Test]# echo 'aaaaaa_bbbbbbb_cccccc_ddddd'|tr -t 'abcd' '123'
111111_2222222_333333_ddddd
[root@localhost Linux_Test]#

这里的SET1为abcd,SET2为123,SET1比SET2长,加上-t参数后,SET1将被截断到SET2相同的长度,也就是’abc’。

删除空行

删除空行
要删除空白行,只需挤压重复的换行符:

1
tr -s '\n' < tr_1.txt > tr_2.txt

在上面的命令中,我们使用重定向符号将命令 < 的内容作为输入传递 file.txt 给 tr 命令。重定向 > 将命令的输出写入 new_file.txt 。
运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost Linux_Test]# cat tr_1.txt 
1
2




7
8
[root@localhost Linux_Test]# tr -s '\n' < tr_1.txt > tr_2.txt
[root@localhost Linux_Test]# cat tr_2.txt
1
2
7
8
[root@localhost Linux_Test]#

在单独的行上打印 $PATH 目录

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost Linux_Test]# echo $PATH
/opt/java/jdk1.8.0_281/bin:/opt/java/jdk1.8.0_281/jre/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/git/bin:/root/bin
[root@localhost Linux_Test]# echo $PATH |tr ':' '\n'
/opt/java/jdk1.8.0_281/bin
/opt/java/jdk1.8.0_281/jre/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin
/usr/local/git/bin
/root/bin
[root@localhost Linux_Test]#

到目前为止,您应该很好地理解如何使用 Linux tr 命令。虽然非常有用, tr 但只能使用单个字符。对于更复杂的模式匹配和字符串操作,您应该使用 sed 或 awk 。

删除所有非数字字符

1
echo "my phone is 123-456-7890" | tr -cd [:digit:]

[:digit:] 代表所有数字字符,通过使用该 -c 选项,该命令将删除所有非数字字符。输出将如下所示:

1
2
[root@localhost Linux_Test]# echo "my phone is 123-456-7890" | tr -cd [:digit:]
1234567890[root@localhost Linux_Test]#

1234567890

参考资料

https://wangchujiang.com/linux-command/c/tr.html
https://www.linuxidc.com/Linux/2019-08/159907.htm
https://www.cnblogs.com/linyfeng/p/9075062.html
https://www.linuxcool.com/tr

如何确保手机和电脑在同一网络下

  • 电脑和手机链接到同一个WiFi下,
    • 这种方式可能会失败,
    • 我在电脑上和手机上分别登录到校园网后,使用Xshell链接不成功,估计是校园网有限制吧,这个问题,浪费我好长时间!,最后发现可以通过热点进行连接
  • 电脑链接到手机热点上
  • 手机链接到电脑的热点上
  • 手机USB线连接电脑,然后打开手机上的USB共享网络

经过我的测试两种热点连接方式都可以通过Xshell连接到手机上的Termux,所以,最好使用热点方式,或者USB共享网络。
还有就是有时候手机或者电脑会断网,可以使用热点方式就不一定有效了,而使用USB共享网络没有这个限制。

Linux sort命令:对文本文件的行排序

sort 是 Linux 的排序命令,而且可以依据不同的数据类型来进行排序。sort 将文件的每一行作为一个单位,相互比较。比较原则是从首字符向后,依次按 ASCII 码值进行比较,最后将它们按升序输出。

Sort是用于对单个或多个文本文件内容进行排序的Linux程序。Sort命令以空格作为字段分隔符,将一行分割为多个关键字对文件进行排序。需要注意的是除非你将输出重定向到文件中,否则Sort命令并不对文件内容进行实际的排序(即文件内容没有修改),只是将文件内容按有序输出。

sort选项:

-f:忽略大小写;
-b:忽略每行前面的空白部分;
-n:以数值型进行排序,默认使用字符串排序;
-r:反向排序;
-u:删除重复行。就是 uniq 命令;
-t:指定分隔符,默认分隔符是制表符;
-k [n,m]:按照指定的字段范围排序。从第 n 个字段开始,到第 m 个字(默认到行尾);

sort 命令默认是用每行开头的第一个字符来进行排序的,比如:

sort –help

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
[root@localhost Linux_Test]# sort --help
用法:sort [选项]... [文件]...
 或:sort [选项]... --files0-from=F
Write sorted concatenation of all FILE(s) to standard output.

Mandatory arguments to long options are mandatory for short options too.
排序选项:

-b, --ignore-leading-blanks 忽略前导的空白区域
-d, --dictionary-order 只考虑空白区域和字母字符
-f, --ignore-case 忽略字母大小写
-g, --general-numeric-sort compare according to general numerical value
-i, --ignore-nonprinting consider only printable characters
-M, --month-sort compare (unknown) < 'JAN' < ... < 'DEC'
-h, --human-numeric-sort 使用易读性数字(例如: 2K 1G)
-n, --numeric-sort 根据字符串数值比较
-R, --random-sort 根据随机hash 排序
--random-source=文件 从指定文件中获得随机字节
-r, --reverse 逆序输出排序结果
--sort=WORD 按照WORD 指定的格式排序:
一般数字-g,高可读性-h,月份-M,数字-n,
随机-R,版本-V
-V, --version-sort 在文本内进行自然版本排序

其他选项:

--batch-size=NMERGE 一次最多合并NMERGE 个输入;如果输入更多
则使用临时文件
-c, --check, --check=diagnose-first 检查输入是否已排序,若已有序则不进行操作
-C, --check=quiet, --check=silent 类似-c,但不报告第一个无序行
--compress-program=程序 使用指定程序压缩临时文件;使用该程序
的-d 参数解压缩文件
--debug 为用于排序的行添加注释,并将有可能有问题的
用法输出到标准错误输出
--files0-from=文件 从指定文件读取以NUL 终止的名称,如果该文件被
指定为"-"则从标准输入读文件名
-k, --key=KEYDEF sort via a key; KEYDEF gives location and type
-m, --merge merge already sorted files; do not sort
-o, --output=文件 将结果写入到文件而非标准输出
-s, --stable 禁用last-resort 比较以稳定比较算法
-S, --buffer-size=大小 指定主内存缓存大小
-t, --field-separator=分隔符 使用指定的分隔符代替非空格到空格的转换
-T, --temporary-directory=目录 使用指定目录而非$TMPDIR 或/tmp 作为
临时目录,可用多个选项指定多个目录
--parallel=N 将同时运行的排序数改变为N
-u, --unique 配合-c,严格校验排序;不配合-c,则只输出一次排序结果
-z, --zero-terminated 以0 字节而非新行作为行尾标志
--help 显示此帮助信息并退出
--version 显示版本信息并退出

KEYDEF is F[.C][OPTS][,F[.C][OPTS]] for start and stop position, where F is a
field number and C a character position in the field; both are origin 1, and
the stop position defaults to the line's end. If neither -t nor -b is in
effect, characters in a field are counted from the beginning of the preceding
whitespace. OPTS is one or more single-letter ordering options [bdfgiMhnRrV],
which override global ordering options for that key. If no key is given, use
the entire line as the key.

SIZE may be followed by the following multiplicative suffixes:
内存使用率% 1%,b 1、K 1024 (默认),M、G、T、P、E、Z、Y 等依此类推。

如果不指定文件,或者文件为"-",则从标准输入读取数据。

*** 警告 ***
本地环境变量会影响排序结果。
如果希望以字节的自然值获得最传统的排序结果,请设置LC_ALL=C。

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
请向<http://translationproject.org/team/zh_CN.html> 报告sort 的翻译错误
要获取完整文档,请运行:info coreutils 'sort invocation'
[root@localhost Linux_Test]#

man sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
SORT(1)                                                                   FSF                                                                  SORT(1)

NAME(名称)
sort - 对文本文件的行排序

SYNOPSIS(总览)
../src/sort [OPTION]... [FILE]...

DESCRIPTION(描述)
在这儿添加任何附加的描述信息

将排序好的所有文件串写到标准输出上.

+POS1 [-POS2]
从关键字POS1开始,到POS2*之前*结束(快过时了) 字段数和字符偏移量都从零开始计数(与-k选项比较)

-b 忽略排序字段或关键字中开头的空格

-c 检查是否指定文件已经排序好了,不排序.

-d 在关键字中只考虑[a-zA-Z0-9]字符.

-f 将关键字中的小写字母折合成大写字母.

-g 按照通常的数字值顺序作比较,暗含-b

-i 在关键字中只考虑[\040-\0176]字符.

-k POS1[,POS2]
从关键字POS1开始,*到*POS2结束. 字段数和字符偏移量都从1开始计数(与基于零的+POS格式作比较)

-l 按照当前环境排序.

-m 合并已经排序好的文件,不排序.

-M 按(未知的)<`JAN'<...<`DEC'的顺序比较,暗含-b

-n 按照字符串的数值顺序比较,暗含-b

-o FILE
将结果写入FILE而不是标准输出.

-r 颠倒比较的结果.

-s 通过屏蔽最后的再分类比较来稳定排序.

-t SEP 使用SEP来替代空格的转换non-.

-T DIRECTORY
使用DIRECTORY作为临时文件,而不是$TMPDIR或者/tmp

-u 如果有-c,则按严格的顺序进行检查; 如果有-m,则只输出相等顺序的第一个.

-z 以0字节结束行,而不是使用换行符,这是为了找到-print0

--help 显示帮助并退出.

--version
输出版本信息并退出.

-t SEP 使用SEP来替代空格的转换non-.

-T DIRECTORY
使用DIRECTORY作为临时文件,而不是$TMPDIR或者/tmp

-u 如果有-c,则按严格的顺序进行检查; 如果有-m,则只输出相等顺序的第一个.

-z 以0字节结束行,而不是使用换行符,这是为了找到-print0

--help 显示帮助并退出.

--version
输出版本信息并退出.

POS为F[.C][OPTS],这里的F指的是字段数,而C为字段中的字符位置,这在-k中是从开
始计数的,而在过时的格式中是从零开始的.OPTS可由一个或多个Mbdfinr组成;这有效地屏蔽了
对于那个关键字的全局-Mbdfinr设置.如果没有指定关键字,则使用整行作为关键字.如 果没有FILE,或者FILE是-,则从标准输入读取.

sort排序示例

sort 文件:默认排序( 整行进行ASCII字符升序)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost Linux_Test]# cat sortFile.txt 
211
121
54
65
87
98
[root@localhost Linux_Test]# sort sortFile.txt
121
211
54
65
87
98
[root@localhost Linux_Test]#

sort -c:检查是否已经排好序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost Linux_Test]# cat sortFile.txt 
211.123
121.321
54.9
54
65
65
65
87
98
1.234E10
[root@localhost Linux_Test]# sort -c sortFile.txt
sort:sortFile.txt:2:无序: 121.321
[root@localhost Linux_Test]#

sort -n:数字按照算术值大小排序

-n 选项 Numberic 对于 数字按照算术值大小排序,而不是按照字符串比较
规则,例如 123 与 67
按算术值排序的话123比67大,如果按照字符串排序的话67比123大。

按字符串排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost Linux_Test]# vim sortFile.txt 
[root@localhost Linux_Test]# cat sortFile.txt
211
121
54
65
87
98
[root@localhost Linux_Test]# sort sortFile.txt
121
211
54
65
87
98
[root@localhost Linux_Test]#

sort -g:浮点数排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost Linux_Test]# sort -n sortFile.txt 
1.234E10
54
54.9
65
65
65
87
98
121.321
211.123
[root@localhost Linux_Test]# sort -g sortFile.txt
54
54.9
65
65
65
87
98
121.321
211.123
1.234E10
[root@localhost Linux_Test]#

sort -n和sort -g的区别

1
2
3
4
-g, --general-numeric-sort
compare according to general numerical value
-n, --numeric-sort
compare according to string numerical value

https://stackoverflow.com/questions/1255782/whats-the-difference-between-general-numeric-sort-and-numeric-sort-options

  • 通用数字排序(-g)将数字比较为浮点数,这可以采用科学记数法,例如1.234E10,但速度较慢并且容易出现舍入错误(1.2345678可能在1.2345679之后).
  • 数字排序(-n)只是一种常规的字母排序,知道10在9之后。

按数值排序

1
2
3
4
5
6
7
8
[root@localhost Linux_Test]# sort -n sortFile.txt 
54
65
87
98
121
211
[root@localhost Linux_Test]#

sort -u:去除排序结果中的重复行

它的作用很简单,就是在输出行中去除重复行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@localhost Linux_Test]# cat sortFile.txt 
211
121
54
54
65
65
65
87
98
[root@localhost Linux_Test]# sort -n sortFile.txt
54
54
65
65
65
87
98
121
211
[root@localhost Linux_Test]# sort -n -u sortFile.txt
54
65
87
98
121
211
[root@localhost Linux_Test]#

sort -r:降序排序

sort默认的排序方式是升序,如果想改成降序,就加个-r就搞定了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[root@localhost Linux_Test]# cat sortFile.txt 
211
121
54
54
65
65
65
87
98
[root@localhost Linux_Test]# sort -n sortFile.txt
54
54
65
65
65
87
98
121
211
[root@localhost Linux_Test]# sort -n -r sortFile.txt
211
121
98
87
65
65
65
54
54
[root@localhost Linux_Test]#

sort -o 文件:将结果写入到文件而非标准输出

由于sort默认是把结果输出到标准输出,所以需要用重定向才能将结果写入文件,形如

1
sort filename > newfile

但是,如果你想把排序结果输出到原文件中,用重定向可就不行了。

1
2
3
4
5
6
7
8
9
10
[root@localhost Linux_Test]# cat sortFile.txt 
98
87
65
54
32
21
[root@localhost Linux_Test]# sort sortFile.txt >sortFile.txt
[root@localhost Linux_Test]# cat sortFile.txt
[root@localhost Linux_Test]#

可以看到,将文件排序后再重定向到该文件后,该文件的内容会被清空。
就在这个时候,-o选项出现了,它成功的解决了这个问题,让你放心的将结果写入原文件。这或许也是-o比重定向的唯一优势所在。

将原文件的内容排序后覆盖原文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost Linux_Test]# vim sortFile.txt 
[root@localhost Linux_Test]# cat sortFile.txt
98
87
65
54
32
21
[root@localhost Linux_Test]# sort sortFile.txt -o sortFile.txt
[root@localhost Linux_Test]# cat sortFile.txt
21
32
54
65
87
98
[root@localhost Linux_Test]#

如果想要指定排序的字段,则需要使用”-t”选项指定分隔符,并使用”-k”选项指定字段号。

sort -t:指定分隔符

默认分隔符是制表符;
对于特殊符号(如制表符),可使用类似于-t$’\t’或-t’ctrl+v,tab’(先按ctrl+v,然后按tab键)的方法实现。

sort -k [n,m]:按照指定的字段范围排序。

从第 n 个字段开始,到第 m 个字(默认到行尾);
测试文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost Linux_Test]# cat ls_l_out.txt 
总用量 120
-rw-r--r--. 1 root root 36 4月 24 13:44 cat_test.txt
-rw-r--r--. 1 root root 30 4月 20 18:21 date_test.txt
-rw-r--r--. 1 root root 592 4月 24 13:19 info_a.log
-rw-r--r--. 1 root root 294 4月 23 14:14 less_test.txt
-rw-r--r--. 1 root root 0 4月 26 15:44 ls_l_out.txt
-rw-r--r--. 1 root root 75517 4月 23 14:21 man_less.txt
-rw-r--r--. 1 root root 9 4月 22 16:47 more_test2.txt
-rw-r--r--. 1 root root 23 4月 22 17:04 more_test3.txt
-rw-r--r--. 1 root root 83 4月 22 17:19 more_test4.txt
-rw-r--r--. 1 root root 294 4月 22 16:22 more_test.txt
-rw-r--r--. 1 root root 48 4月 26 15:38 sortFile.txt
-rw-r--r--. 1 root root 27 4月 14 01:48 vi_replaceAllTest.txt
-rw-r--r--. 1 root root 36 4月 24 14:00 wc_test.txt
[root@localhost Linux_Test]#

按第5个字段进行排序:

[root@localhost Linux_Test]# sort -k 5,5 ls_l_out.txt 
总用量 120
-rw-r--r--. 1 root root     0 4月  26 15:44 ls_l_out.txt
-rw-r--r--. 1 root root    23 4月  22 17:04 more_test3.txt
-rw-r--r--. 1 root root    27 4月  14 01:48 vi_replaceAllTest.txt
-rw-r--r--. 1 root root   294 4月  22 16:22 more_test.txt
-rw-r--r--. 1 root root   294 4月  23 14:14 less_test.txt
-rw-r--r--. 1 root root    30 4月  20 18:21 date_test.txt
-rw-r--r--. 1 root root    36 4月  24 13:44 cat_test.txt
-rw-r--r--. 1 root root    36 4月  24 14:00 wc_test.txt
-rw-r--r--. 1 root root    48 4月  26 15:38 sortFile.txt
-rw-r--r--. 1 root root   592 4月  24 13:19 info_a.log
-rw-r--r--. 1 root root 75517 4月  23 14:21 man_less.txt
-rw-r--r--. 1 root root    83 4月  22 17:19 more_test4.txt
-rw-r--r--. 1 root root     9 4月  22 16:47 more_test2.txt
[root@localhost Linux_Test]# 

按第9个字段排序:

[root@localhost Linux_Test]# sort -k 9,9 ls_l_out.txt 
总用量 120
-rw-r--r--. 1 root root    36 4月  24 13:44 cat_test.txt
-rw-r--r--. 1 root root    30 4月  20 18:21 date_test.txt
-rw-r--r--. 1 root root   592 4月  24 13:19 info_a.log
-rw-r--r--. 1 root root   294 4月  23 14:14 less_test.txt
-rw-r--r--. 1 root root     0 4月  26 15:44 ls_l_out.txt
-rw-r--r--. 1 root root 75517 4月  23 14:21 man_less.txt
-rw-r--r--. 1 root root     9 4月  22 16:47 more_test2.txt
-rw-r--r--. 1 root root    23 4月  22 17:04 more_test3.txt
-rw-r--r--. 1 root root    83 4月  22 17:19 more_test4.txt
-rw-r--r--. 1 root root   294 4月  22 16:22 more_test.txt
-rw-r--r--. 1 root root    48 4月  26 15:38 sortFile.txt
-rw-r--r--. 1 root root    27 4月  14 01:48 vi_replaceAllTest.txt
-rw-r--r--. 1 root root    36 4月  24 14:00 wc_test.txt
[root@localhost Linux_Test]#

当然,”-k”选项可以直接使用”-k 9”,代表从第三个字段到行尾都排序(第一个字段先排序,如果一致,则第二个字段再排序,直到行尾)。

sort -t ‘分隔符’ -k 开始字段,结束字段

测试文件:

1
2
3
4
5
6
7
[root@localhost Linux_Test]# cat sort_t_k.txt 
bnana:30:5.5
bnana:12:9.8
apple:10:2.5
pear:90:2.3
orange:20:3.4
[root@localhost Linux_Test]#

这个文件有三列,列与列之间用冒号隔开了,第一列表示水果类型,第二列表示水果数量,第三列表示水果价格。

那么我想以水果价格来排序,也就是以第3列来排序,如何利用sort实现?
幸好,sort提供了-t选项,后面可以设定间隔符。
指定了间隔符之后,就可以用-k来指定列数了。

[root@localhost Linux_Test]# sort -t ':' -k 3,3 sort_t_k.txt 
pear:90:2.3
apple:10:2.5
orange:20:3.4
bnana:30:5.5
bnana:12:9.8
[root@localhost Linux_Test]#

按第2列进行排序:

[root@localhost Linux_Test]# sort -t ':' -k 2,2 sort_t_k.txt 
apple:10:2.5
bnana:12:9.8
orange:20:3.4
bnana:30:5.5
pear:90:2.3
[root@localhost Linux_Test]# 

按第1列到第2列进行排序

[root@localhost Linux_Test]# sort -t ':' -k 1,2 sort_t_k.txt 
apple:10:2.5
bnana:12:9.8
bnana:30:5.5
orange:20:3.4
pear:90:2.3
[root@localhost Linux_Test]#

参考资料

http://c.biancheng.net/view/996.html
https://www.cnblogs.com/51linux/archive/2012/05/23/2515299.html
https://man.linuxde.net/sort
http://fancyerii.github.io/2019/06/15/sort/
https://www.linuxidc.com/Linux/2017-08/146605.htm

Linux wc命令

功能

  • 列出文件中一共有多少行,有多少个单词,多少字符
  • 当指定的文件数大于 1 时,最后还列出一个合计
  • 常用选项l:只列出行计数

man wc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
WC(1)                                                                           FSF                                                                          WC(1)

NAME
wc - 输出文件中的行数、单词数、字节数

SYNOPSIS 总览
wc [选项列表]... [文件名列表]...

SYNOPSIS 总览
wc [选项列表]... [文件名列表]...

DESCRIPTION 描述
对每个文件输出行、单词、和字节统计数,如果指定了多于一个文件则还有一 个行数的总计。没有指定文件或指定的文件是 -,则读取标准输入。

-c, --bytes, --chars
输出字节统计数。

-l, --lines
输出换行符统计数。

-L, --max-line-length
输出最长的行的长度。

-w, --words
输出单词统计数。

--help 显示帮助并退出

--version
输出版本信息并退出

AUTHOR 著作者
由 Paul Rubin 和 David MacKenzie 完成。

wc命令参数

wc命令参数 描述
-w或–words 统计字数:只显示字数。一个字被定义为由空白、跳格或换行字符分隔的字符串
-c或–bytes或–chars 统计字节数:只显示Bytes数
-l或–lines 统计行数,只显示列数
-m 统计字符数
-L 打印最长行的长度

wc命令示例

测试文件

1
2
3
[root@localhost Linux_Test]# cat cat_test.txt 
hello world!
Welcome to learn Linux
1
2
3
[root@localhost Linux_Test]# cat wc_test.txt 
The current Linux release is CentOS
[root@localhost Linux_Test]#

wc 文件:统计行数、单词数、字节数

1
2
3
[root@localhost Linux_Test]# wc cat_test.txt 
2 6 36 cat_test.txt
[root@localhost Linux_Test]#

直接使用wc 文件命令输出的前3个数字分别表示文件的行数、单词数,以及该文件的字节数。

wc -c 文件:统计文件中的字节数

1
2
3
[root@localhost Linux_Test]# wc -c cat_test.txt 
36 cat_test.txt
[root@localhost Linux_Test]#

wc -w 文件:统计文件中的单词数

1
2
3
[root@localhost Linux_Test]# wc -w cat_test.txt 
6 cat_test.txt
[root@localhost Linux_Test]#

wc -l 文件:统计文件行数

1
2
3
[root@localhost Linux_Test]# wc -l cat_test.txt 
2 cat_test.txt
[root@localhost Linux_Test]#

wc -L 文件:统计文件中最长的行的长度

1
2
3
[root@localhost Linux_Test]# wc -L cat_test.txt 
22 cat_test.txt
[root@localhost Linux_Test]#

wc 多个文件

1
2
3
4
5
[root@localhost Linux_Test]# wc cat_test.txt wc_test.txt 
2 6 36 cat_test.txt
1 6 36 wc_test.txt
3 12 72 总用量
[root@localhost Linux_Test]#

组合命令

只统计文件的行数、字数、字节数不显示文件名

cat 文件|wc -l:

1
2
3
4
5
6
7
8
9
[root@localhost Linux_Test]# cat cat_test.txt |wc
2 6 36
[root@localhost Linux_Test]# cat cat_test.txt |wc -l
2
[root@localhost Linux_Test]# cat cat_test.txt |wc -w
6
[root@localhost Linux_Test]# cat cat_test.txt |wc -c
36
[root@localhost Linux_Test]#

wc -l < 文件

1
2
3
4
5
6
7
8
9
[root@localhost Linux_Test]# wc < cat_test.txt 
2 6 36
[root@localhost Linux_Test]# wc -l < cat_test.txt
2
[root@localhost Linux_Test]# wc -w < cat_test.txt
6
[root@localhost Linux_Test]# wc -c < cat_test.txt
36
[root@localhost Linux_Test]#

wc -l *:统计当前目录下的所有文件的行数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost Linux_Test]# wc -l *
2 cat_test.txt
2 date_test.txt
10 info_a.log
36 less_test.txt
8 ls_out.txt
5 ls_sort.txt
1185 man_less.txt
6 more_test2.txt
12 more_test3.txt
36 more_test4.txt
36 more_test.txt
6 sortFile.txt
6 vi_replaceAllTest.txt
1 wc_test.txt
1351 总用量
[root@localhost Linux_Test]#

统计当前系统中有多少账户

1
2
3
[root@localhost Linux_Test]# cat /etc/passwd |wc -l
123
[root@localhost Linux_Test]#

ps ef | wc -l:统计系统当前有多少个进程在运行

1
2
3
[root@localhost blog]# ps ef | wc -l
6
[root@localhost blog]#

参考资料

https://www.runoob.com/linux/linux-comm-wc.html
https://www.cnblogs.com/peida/archive/2012/12/18/2822758.html
https://wangchujiang.com/linux-command/c/wc.html
https://blog.csdn.net/Jerry_1126/article/details/52107947

tee命令功能

将从标准输入 stdin 得到的数据抄送到标准输出 stdout 显示 ,同时存入磁盘文件中
简单的说就是把数据重定向到给定文件和屏幕上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost 2021年04月]# tee --help
用法:tee [选项]... [文件]...
将标准输入复制到每个指定文件,并显示到标准输出。

-a, --append 内容追加到给定的文件而非覆盖
-i, --ignore-interrupts 忽略中断信号
--help 显示此帮助信息并退出
--version 显示版本信息并退出

如果文件指定为"-",则将输入内容复制到标准输出。

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
请向<http://translationproject.org/team/zh_CN.html> 报告tee 的翻译错误
要获取完整文档,请运行:info coreutils 'tee invocation'
[root@localhost 2021年04月]#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
TEE(1)                                                                          FSF                                                                         TEE(1)

NAME
tee - 从标准输入写往文件和标准输出

总览 (SYNOPSIS)
tee [OPTION]... [FILE]...

描述 (DESCRIPTION)
把 标准输入 的 数据 复制到 每一个 文件 FILE, 同时 送往 标准输出.
TEE(1) FSF TEE(1)

NAME
tee - 从标准输入写往文件和标准输出

总览 (SYNOPSIS)
tee [OPTION]... [FILE]...

描述 (DESCRIPTION)
把 标准输入 的 数据 复制到 每一个 文件 FILE, 同时 送往 标准输出.

-a, --append
追加到 给出的 文件, 而不是 覆盖

tee - 从标准输入写往文件和标准输出

总览 (SYNOPSIS)
tee [OPTION]... [FILE]...

描述 (DESCRIPTION)
把 标准输入 的 数据 复制到 每一个 文件 FILE, 同时 送往 标准输出.

-a, --append
追加到 给出的 文件, 而不是 覆盖

-i, --ignore-interrupts
忽略 中断信号

--help 显示 帮助信息, 然后 结束

--version
显示 版本信息, 然后 结束

tee示例

ls | tee 文件

在终端打印stdout同时重定向到文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@localhost 2021年04月]# ls | tee out.txt
2021年04月09日Linux专项练习1.md
2021年04月11日Linux专项练习1.md
2021年04月12日Linux专项练习1.md
2021年04月12日Linux专项练习2.md
2021年04月12日Linux专项练习3.md
2021年04月17日Linux专项联系1.md
2021年04月18日Linux专项练习1.md
2021年04月18日Linux专项练习2.md
2021年04月18日Linux专项练习3.md
2021年04月18日Linux专项练习4.md
2021年04月18日Linux专项练习5.md
out.txt
[root@localhost 2021年04月]# cat out.txt
2021年04月09日Linux专项练习1.md
2021年04月11日Linux专项练习1.md
2021年04月12日Linux专项练习1.md
2021年04月12日Linux专项练习2.md
2021年04月12日Linux专项练习3.md
2021年04月17日Linux专项联系1.md
2021年04月18日Linux专项练习1.md
2021年04月18日Linux专项练习2.md
2021年04月18日Linux专项练习3.md
2021年04月18日Linux专项练习4.md
2021年04月18日Linux专项练习5.md
out.txt
[root@localhost 2021年04月]#

ps -ef |tee 文件

将进程信息通过管道输出到标准输出(终端)并覆盖写入到文件中。

1
ps -ef |tee info_a.log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[root@localhost Linux_Test]# ps -ef|head|tee info_a.log
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 4月21 ? 00:02:42 /init
root 2 0 0 4月21 ? 00:00:00 [kthreadd]
root 3 2 0 4月21 ? 00:04:01 [ksoftirqd/0]
root 7 2 0 4月21 ? 00:07:22 [rcu_preempt]
root 8 2 0 4月21 ? 00:00:00 [rcu_bh]
root 9 2 0 4月21 ? 00:00:01 [rcu_sched]
root 10 2 0 4月21 ? 00:01:09 [migration/0]
root 11 2 0 4月21 ? 00:00:44 [migration/1]
root 12 2 0 4月21 ? 00:02:51 [ksoftirqd/1]
[root@localhost Linux_Test]# ls
cat_test.txt info_a.log ls_out.txt man_less.txt more_test3.txt more_test.txt vi_replaceAllTest.txt
date_test.txt less_test.txt ls_sort.txt more_test2.txt more_test4.txt sortFile.txt
[root@localhost Linux_Test]# cat info_a.log
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 4月21 ? 00:02:42 /init
root 2 0 0 4月21 ? 00:00:00 [kthreadd]
root 3 2 0 4月21 ? 00:04:01 [ksoftirqd/0]
root 7 2 0 4月21 ? 00:07:22 [rcu_preempt]
root 8 2 0 4月21 ? 00:00:00 [rcu_bh]
root 9 2 0 4月21 ? 00:00:01 [rcu_sched]
root 10 2 0 4月21 ? 00:01:09 [migration/0]
root 11 2 0 4月21 ? 00:00:44 [migration/1]
root 12 2 0 4月21 ? 00:02:51 [ksoftirqd/1]
[root@localhost Linux_Test]#

将进程信息通过管道输出到标准输出(终端)并追加写入到文件中。

1
ps -ef |tee -a info_a.log info_b.log

参考资料

https://zhuanlan.zhihu.com/p/34510815
https://linux.cn/article-9435-1.html
https://man.linuxde.net/tee