分享

linux命令行文本操作一文就够

 健明 2021-07-14

主要是 awk/grep/sed这三驾马车,加上vi这个神器,最后辅助一些小工具,包括 wc,cat,diff,join,paste,cut,uniq

这里 简要地整理下Linux用来处理数据文本的工具。具体命令详情请在Linux命令大全中搜索或者查阅其他相关资料。

headtail查看文档头尾。 -n选项可以指定行数。

less用来查阅文档, q退出, space bar翻页, g第一行, G最后一行, j下, k上, /<pattern>往下搜索模式, ?<pattern>往上搜索模式, n前一个匹配字符, N后一个匹配字符。

less可以用于debug,查看中间输出结果。比如

  1. step1 input.txt | step2 | step3 > output.txt

  2. # step1,2,3为程序或命令名

可以写为

  1. step1 input.txt | less

  2. step1 input.txt | step2 | less

  3. step1 input.txt | step2 | step3 | less

这样就可以一步步的查看中间结果啦~

用man可以查看less的详细手册,而且 在此生信技能树的公众号后台回复 马哥 可以拿到详细的视频讲解,这里就不多说了,注意两个参数即可,分别是 -S 和 -N ,赶快试一下吧。

同理还有 more 命令, cat 命令也可以查看文本。

纯文本信息汇总

wc命令默认依次输出单词数、行数、总字符数。查看行数使用 wc -l。 如果存在空行,空行会被计数。可以使用 grep命令实现非空行计数 grep -"[^ \\n\\t]" some_data.bed

ls -lh以易读形式查看文件大小。

输出文件列数:

  1. # -F指定分隔符,此处假定是table键分隔,默认空格键

  2. awk -F "\t" '{print NF; exit}' some_data.bed

怎么去除注释的元数据行呢?怎么计数非注释行行数呢?

可以使用 tail结合 awk,试试gtf(基因组注释文件)

  1. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ head -n 6 Homo_sapiens.GRCh37.75.gtf

  2. #!genome-build GRCh37.p13

  3. #!genome-version GRCh37

  4. #!genome-date 2009-02

  5. #!genome-build-accession NCBI:GCA_000001405.14

  6. #!genebuild-last-updated 2013-09

  7. 1    pseudogene  gene    11869   14412   .   +   .   gene_id "ENSG00000223972"; gene_name "DDX11L1"; gene_source "ensembl_havana"; gene_biotype "pseudogene";

可以看到注释行是5行,我们利用 tail试试去掉它

  1. # 注意此处 -n后接的"+"号

  2. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ tail -n +5 Homo_sapiens.GRCh37.75.gtf | head -n 1

  3. #!genebuild-last-updated 2013-09

发现还有一行没去掉

  1. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ tail -n +6 Homo_sapiens.GRCh37.75.gtf | head -n 1

  2. 1    pseudogene  gene    11869   14412   .   +   .   gene_id "ENSG00000223972"; gene_name "DDX11L1"; gene_source "ensembl_havana"; gene_biotype "pseudogene";

成功搞定,然后结合前面提到的 awk命令即可计算行数。

上面方法鲁棒性不够(人为地确定行数),一种更为通用的方法是 grep结合 awk命令

  1. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ grep -v "^#" Homo_sapiens.GRCh37.75.gtf | head -n 1

  2. 1    pseudogene  gene    11869   14412   .   +   .   gene_id "ENSG00000223972"; gene_name "DDX11L1"; gene_source "ensembl_havana"; gene_biotype "pseudogene";

推荐使用这种。

cut 详解

cut可以处理列数据, -f选项指定列,可以是一个范围(比如2-8),注意不能用它给列排序。

  1. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ grep -v "^#" Homo_sapiens.GRCh37.75.gtf | head -n 10 | cut -f 3

  2. gene

  3. transcript

  4. exon

  5. exon

  6. exon

  7. transcript

  8. exon

  9. exon

  10. exon

  11. transcript

  12. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ grep -v "^#" Homo_sapiens.GRCh37.75.gtf | head -n 10 | cut -f 3-5

  13. gene    11869   14412

  14. transcript    11869   14409

  15. exon    11869   12227

  16. exon    12613   12721

  17. exon    13221   14409

  18. transcript    11872   14412

  19. exon    11872   12227

  20. exon    12613   12721

  21. exon    13225   14412

  22. transcript    11874   14409

-d选项可以指定分隔符,比如 -d,指定 ,为分隔符。

使用 column命令来格式化输出,上次的命令结果输出明显没对齐,我们把它对齐看看:

  1. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ grep -v "^#" Homo_sapiens.GRCh37.75.gtf | head -n 10 | cut -f 3-5 | column -t

  2. gene 11869 14412

  3. transcript 11869 14409

  4. exon 11869 12227

  5. exon 12613 12721

  6. exon 13221 14409

  7. transcript 11872 14412

  8. exon 11872 12227

  9. exon 12613 12721

  10. exon 13225 14412

  11. transcript 11874 14409

注意,使用这个命令是为了好观察,不要把用它处理然后把结果传入文本(会导致程序处理文件效率降低,因为文本解析速度会下降)。

cut和 column默认以 \t为分隔符,这里也能够用 -s选项指定。

先把之前的tab分隔文件弄成逗号分隔文件,然后使用 -s选项看看:

  1. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ grep -v "^#" Homo_sapiens.GRCh37.75.gtf | head -n 10 | cut -f 3-5 | awk '{FS="\t";OFS=",";}{print $1,$2,$3}'

  2. gene,11869,14412

  3. transcript,11869,14409

  4. exon,11869,12227

  5. exon,12613,12721

  6. exon,13221,14409

  7. transcript,11872,14412

  8. exon,11872,12227

  9. exon,12613,12721

  10. exon,13225,14412

  11. transcript,11874,14409

  12. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ grep -v "^#" Homo_sapiens.GRCh37.75.gtf | head -n 10 | cut -f 3-5 | awk '{FS="\t";OFS=",";}{print $1,$2,$3}'| column -s "," -t

  13. gene 11869 14412

  14. transcript 11869 14409

  15. exon 11869 12227

  16. exon 12613 12721

  17. exon 13221 14409

  18. transcript 11872 14412

  19. exon 11872 12227

  20. exon 12613 12721

  21. exon 13225 14412

  22. transcript 11874 14409

grep 简单了解

grep处理速度非常之快,能用它尽量用它。 --color=auto可以激活颜色(标记匹配文字),更方便查看。

-v选项排除匹配到的, -w进行完全匹配。这样可以防止,你想排除 abc结果把 abc1, abcd也排除掉了。

-B指定输出包括匹配到的前多少行,比如 -B1就是前一行; -A指定输出包括匹配到的后多少行,比如 -A2就是包括了后两行。 -C指定输出包括匹配到的前后多少行。 grep支持基本正则表达式, -E指定支持扩展表达式,或者用 egrep命令。 -c选项对匹配的行计数; -o选项只抽离输出匹配的部分

  1. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ grep -E -o 'gene_id "\w+"' Homo_sapiens.GRCh37.75.gtf | head -n 5

  2. gene_id "ENSG00000223972"

  3. gene_id "ENSG00000223972"

  4. gene_id "ENSG00000223972"

  5. gene_id "ENSG00000223972"

  6. gene_id "ENSG00000223972"

发现冗余项非常多,如果我们只要唯一的呢,怎么办?

  1. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ grep -E -o 'gene_id "(\w+)"' Homo_sapiens.GRCh37.75.gtf | cut -f2 -d" "| sed 's/"//g' | sort | uniq | head -n 10

  2. ENSG00000000003

  3. ENSG00000000005

  4. ENSG00000000419

  5. ENSG00000000457

  6. ENSG00000000460

  7. ENSG00000000938

  8. ENSG00000000971

  9. ENSG00000001036

  10. ENSG00000001084

  11. ENSG00000001167

虽然我的笔记本呼啦啦作响,但是还是非常快就跑完了。

file查看文件编码

  1. wsx@wsx-ubuntu:~$ file regular_express.txt

  2. regular_express.txt: ASCII text, with CRLF, LF line terminators

常用的大型数据文件一般存为ASCII码形式(像几大基因bank的数据文件),而我们自己认为创建的常为UTF-8,所以有时候认为处理文件需要会碰到把UTF-8编码的字符插入到ASCII码文件里去了。遇到这种问题,我们可以用 hexdump -c命令查看出错的地方(手边没有这样的文件,就不举例了)。

用sort对文本排序

我们先创建一个bed格式文件来试试这个命令:

  1. wsx@wsx-ubuntu:~$ cat test.bed

  2. chr1    26  39

  3. chr3    32  47

  4. chr1    40  50

  5. chr1    9   28

  6. chr2    35  54

  7. chr1    10  19

  8. wsx@wsx-ubuntu:~$ sort test.bed

  9. chr1    10  19

  10. chr1    26  39

  11. chr1    40  50

  12. chr1    9   28

  13. chr2    35  54

  14. chr3    32  47

可以明显看到文本按照第一列进行了排序。 默认, sort用空格或tab键作为域(列)分隔符。如果我们用其他形式的分隔符,需要用 -t选项指定。

下面是对 bed文件最通用的排序命令:

  1. wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2n test.bed

  2. chr1    9   28

  3. chr1    10  19

  4. chr1    26  39

  5. chr1    40  50

  6. chr2    35  54

  7. chr3    32  47

基本操作 bedtools软件都会先用这个命令对 bedtools文件排序。 现在略加解释一下, sort用 -k选项指定某列的排序方式。而每次使用 -k选项都要带上指定列的范围(start, end)。如果只指定一列,就为(start,start)了,像上面命令的 -k1,1就是。也许你会觉得 -k2,2n很奇怪,这里的 n指定程序把第二列当做数值对待。如果不做设定,都是当做字符对待(shell都是这么对待数值数据的)。所以总结其他这一行命令就是对第一列按照字符排序,第二列按照数值排序。

我们可以用 -c选项检查一个文件是不是已经按照过某种方式排过序了。

  1. wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2n test.bed | sort -k1,1 -k2,2 -c

  2. sort:-:2:无序: chr1    10  19

  3. wsx@wsx-ubuntu:~$ echo $?

  4. 1

  5. wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2n test.bed | sort -k1,1 -k2,2n -c

  6. wsx@wsx-ubuntu:~$ echo $?

  7. 0

上面可以清楚地看到 sort是怎么对待文件的(一般shell返回0表示成功执行)。

  1. wsx@wsx-ubuntu:~$ tsfds

  2. tsfds:未找到命令

  3. wsx@wsx-ubuntu:~$ echo $?

  4. 127

  5. wsx@wsx-ubuntu:~$ echo test

  6. test

  7. wsx@wsx-ubuntu:~$ echo $?

  8. 0

shell的命令退出状态码表示了该命令执行的完成的某种情况。不同的状态码有不同的含义,具体可以百度查阅(我之前整理的shell笔记应该讲过,可以看看)。

反向排序用 -r选项。如果你只想反转一列,可以把它加在 -k选项后。

  1. wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2nr test.bed

  2. chr1    40  50

  3. chr1    26  39

  4. chr1    10  19

  5. chr1    9   28

  6. chr2    35  54

  7. chr3    32  47

现在我给 test.bed加一行:

  1. wsx@wsx-ubuntu:~$ cat test.bed

  2. chr1    26  39

  3. chr3    32  47

  4. chr1    40  50

  5. chr1    9   28

  6. chr2    35  54

  7. chr1    10  19

  8. chr11    22  56

你会发现有点奇怪

  1. wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2n test.bed

  2. chr1    9   28

  3. chr1    10  19

  4. chr1    26  39

  5. chr1    40  50

  6. chr11    22  56

  7. chr2    35  54

  8. chr3    32  47

怎么 chr11在 chr2前面?其实 sort排序的方式有点像查字典。例子中,命令先比较 c,然后比较 h,然后比较 r,接着比较 1,自然 11会在 2前面了。这里可以添加 V选项修改。

  1. wsx@wsx-ubuntu:~$ sort -k1,1V -k2,2n test.bed

  2. chr1    9   28

  3. chr1    10  19

  4. chr1    26  39

  5. chr1    40  50

  6. chr2    35  54

  7. chr3    32  47

  8. chr11    22  56

是不是觉得这样更可观一些?不过通常在处理数据时不做此处理,符合 规范的数据可以让后续处理程序效率更高。

基本掌握 sort这些也够用了,它主要为后续处理服务。如果想知道其他的用法,查查吧,同时欢迎发文来交流。

用uniq寻找唯一值

首先创建样例文本

  1. wsx@wsx-ubuntu:~$ cat test.letter

  2. A

  3. A

  4. B

  5. C

  6. B

  7. C

  8. C

  9. C

  10. D

  11. F

  12. D

使用 uniq看看

  1. wsx@wsx-ubuntu:~$ uniq test.letter

  2. A

  3. B

  4. C

  5. B

  6. C

  7. D

  8. F

  9. D

尼玛,怎么不对。它好像只去掉了连续的同一字符。怎么办?想想我们刚学了什么命令? sort不是刚好可以把同样的字符弄到一起去吗,然后再使用 uniq,嘿嘿:

  1. wsx@wsx-ubuntu:~$ sort test.letter | uniq

  2. A

  3. B

  4. C

  5. D

  6. F

哟呵,got you。

加 -c选项计数:

  1. wsx@wsx-ubuntu:~$ sort test.letter | uniq -c

  2. 2 A

  3. 2 B

  4. 4 C

  5. 2 D

  6. 1 F

把结果再排序

  1. wsx@wsx-ubuntu:~$ sort test.letter | uniq -c | sort -rn

  2. 4 C

  3. 2 D

  4. 2 B

  5. 2 A

  6. 1 F

-d选项只输出重复行

  1. wsx@wsx-ubuntu:~$ cat test.letter

  2. A

  3. A

  4. B

  5. C

  6. B

  7. C

  8. C

  9. C

  10. D

  11. F

  12. D

  13. wsx@wsx-ubuntu:~$ uniq -d test.letter

  14. A

  15. C

  16. wsx@wsx-ubuntu:~$ sort test.letter | uniq -d

  17. A

  18. B

  19. C

  20. D

使用时需要注意处理不同导致的结果差异。

Join 命令

用来连接文件。 假设现在我们有两个文件:

  1. wsx@wsx-ubuntu:/tmp$ cat example.bed

  2. chr1    26  39

  3. chr1    32  47

  4. chr3    11  28

  5. chr1    40  49

  6. chr3    16  27

  7. chr1    9   28

  8. chr2    35  53

  9. wsx@wsx-ubuntu:/tmp$ cat example_length.txt

  10. chr1    53453

  11. chr2    34356

  12. chr3    24356

我想把第二个文件说明染色体长度添加到第一个文件对应染色体的第三列。 我们首先要给文件排序(使用 join前必须做),然后使用 join命令。

  1. wsx@wsx-ubuntu:/tmp$ sort -k1,1 example.bed > example_sorted.bed

  2. wsx@wsx-ubuntu:/tmp$ sort -c -k1,1 example_length.txt

  3. wsx@wsx-ubuntu:/tmp$ cat example_sorted.bed

  4. chr1    26  39

  5. chr1    32  47

  6. chr1    40  49

  7. chr1    9   28

  8. chr2    35  53

  9. chr3    11  28

  10. chr3    16  27

  11. wsx@wsx-ubuntu:/tmp$ join -1 1 -2 1 example_sorted.bed example_length.txt > example_with_length.txt

  12. wsx@wsx-ubuntu:/tmp$ cat example_with_length.txt

  13. chr1 26 39 53453

  14. chr1 32 47 53453

  15. chr1 40 49 53453

  16. chr1 9 28 53453

  17. chr2 35 53 34356

  18. chr3 11 28 24356

  19. chr3 16 27 24356

命令基本语法是

  1. join -1 <file_1_field> -2 <file_2_field> <file_1> <file_2>

既然名字叫 join,就是两者必须有共同之处,通过共同的支点将两者连为一体。 -1和 -2选项后接参数分别指定了这个支点,也就是连接的域(列)。比如例子中,都是两个文件的第一列。

两个文件中,第一列都共有 chr1(2)(3)。 如果不一致会出现什么情况呢?

  1. wsx@wsx-ubuntu:/tmp$ join -1 1 -2 1 example_sorted.bed example_length_alt.txt chr1 26 39 53453

  2. chr1 32 47 53453

  3. chr1 40 49 53453

  4. chr1 9 28 53453

  5. chr2 35 53 34356

如果第二个文件没有 chr3, join之后也没了!!

我们可以通过 -a选项指定哪一个文件可以不遵循配对

  1. wsx@wsx-ubuntu:/tmp$ join -1 1 -2 1 -a 1 example_sorted.bed example_length_alt.txt

  2. chr1 26 39 53453

  3. chr1 32 47 53453

  4. chr1 40 49 53453

  5. chr1 9 28 53453

  6. chr2 35 53 34356

  7. chr3 11 28

  8. chr3 16 27

awk 可以说是一门语言了

awk是文本处理的一把好手,虽然它不能像 python, R干一些高级复杂的主题工作,但是它具备完整的命令操作和编程体系。

awk是一门语言,我不可能在学习的时候能够逻辑清晰详细地介绍给大家。主要是还通过实例来了解用法,加深认识。手册可以参考http://man./awk。

首先要明白的是, awk按行处理数据。在shell知识里,如果把一个文档看做一张表。那么一行就是一个记录,一列就是一个。可以看出, awk就是按记录处理文本的。

其次是 awk的程序结构是

  1. pattern {action}

pattern可以是表达式或者正则表达式。pattern有点像 if语句,当它满足时就会执行相应的动作。

另一个 awk核心是它用$0 表示所有列,$1,$2`...等等表示对应的列。我们可以很方便地用它进行操作。

  1. wsx@wsx-ubuntu:/tmp$ awk '{print $0}' example.bed

  2. chr1    26  39

  3. chr1    32  47

  4. chr3    11  28

  5. chr1    40  49

  6. chr3    16  27

  7. chr1    9   28

  8. chr2    35  53

  9. wsx@wsx-ubuntu:/tmp$ awk '{print $1}' example.bed

  10. chr1

  11. chr1

  12. chr3

  13. chr1

  14. chr3

  15. chr1

  16. chr2

  17. wsx@wsx-ubuntu:/tmp$ awk '{print $2}' example.bed

  18. 26

  19. 32

  20. 11

  21. 40

  22. 16

  23. 9

print语句就像动作一样输出你操作的结果。

  1. wsx@wsx-ubuntu:/tmp$ awk '{ print $2 "\t" $3}' example.bed

  2. 26    39

  3. 32    47

  4. 11    28

  5. 40    49

  6. 16    27

  7. 9    28

  8. 35    53

  9. wsx@wsx-ubuntu:/tmp$ awk '{ print $2 $3}' example.bed

  10. 2639

  11. 3247

  12. 1128

  13. 4049

  14. 1627

  15. 928

  16. 3553

  17. wsx@wsx-ubuntu:/tmp$ awk '{ print $2 , $3}' example.bed

  18. 26 39

  19. 32 47

  20. 11 28

  21. 40 49

  22. 16 27

  23. 9 28

  24. 35 53

了解上述几个语句的不同。

表示染色体名一般用带 chr或者不带 chr标志两种方式。当我们要用到这两种时,肯定要让它们能够对应起来,也就是转换。 awk命令可以非常方便地添加 chr标记。

下面我先把例子文件的 chr去掉,然后加上试试。

  1. wsx@wsx-ubuntu:/tmp$ awk '{ print $1}' example.bed

  2. chr1

  3. chr1

  4. chr3

  5. chr1

  6. chr3

  7. chr1

  8. chr2

  9. wsx@wsx-ubuntu:/tmp$ awk '{ print $1}' example.bed | cut -c4

  10. 1

  11. 1

  12. 3

  13. 1

  14. 3

  15. 1

  16. 2

  17. wsx@wsx-ubuntu:/tmp$ awk '{ print $1}' example.bed | cut -c4 | awk '{print "chr"$1}'

  18. chr1

  19. chr1

  20. chr3

  21. chr1

  22. chr3

  23. chr1

  24. chr2

awk作为一门编程语言,它支持各种操作符(运算,逻辑,判断)喔。

  1. wsx@wsx-ubuntu:/tmp$ awk '$3 - $2 >18' example.bed

  2. chr1    9   28

  3. wsx@wsx-ubuntu:/tmp$ awk '$1 ~/chr1/ && $3 - $2 > 10' example.bed

  4. chr1    26  39

  5. chr1    32  47

  6. chr1    9   28

  7. # 这里 ~ 符号用来匹配正则表达式

还有 awk存在一些变量,像 NR表示行号, OFS表示输出分隔符等。

  1. wsx@wsx-ubuntu:/tmp$ awk 'NR >= 3 && NR <= 5' example.bed

  2. chr3    11  28

  3. chr1    40  49

  4. chr3    16  27

如果我们想把 gtf文件转换成为 bed格式,可以使用

  1. wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ head -n1000 Homo_sapiens.GRCh37.75.gtf | awk '!/^#/{ print $1 "\t" $4-1 "\t" $5} ' | head -n 3

  2. 1    11868   14412

  3. 1    11868   14409

  4. 1    11868   12227

因为篇幅有限,我不可能输出所有结果,所以只取部分数据做了运算。

用sed进行流编辑

sed工作流:读取$\to$执行命令$\to$显示。默认情况,所有的命令都会一个叫做在模式空间(pattern buffer)的缓冲区进行。因此不会改变原始输入文件的内容。

语法规则

sed即支持在命令行中用单引号输入执行命令,也支持执行含有sed命令的文件。使用方式如下:

  1. sed [‐n] [‐e] 'command(s)' files

  2. sed [‐n] f script files

选项

sed 后面首先需要跟参数,支持的参数有:

选项与参数: -n :禁止显示所有输入内容,只显示经过sed处理的行(常用) -e :直接在命令列模式上进行 sed 的动作编辑,接要执行的一个或者多个命令 -f :执行含有sed 动作的文件 -r :sed 的动作支持的扩展正则(默认基础正则) -i :直接修改读取的文件内容,不输出。

作用区域

默认情况下,sed命令会作用于文本数据的所有行。如果只想作用于某些行时,则需要使用在命令通过行号或者文本过滤的方式前指明作用区域。

行号

使用数字行号时,类似于R中的向量子集提取。单独数字表示某一行,逗号分割指示行范围,另外 m,+n表示从m行开始向下n行, m~n表示从m行开始的每n行。

例如 sed '2~2 p' test.txt 输出偶数行, sed '1~2 p' test.txt输出奇数行内容。

文本过滤

'/pattern/ command'可以只在包含pattern 的行中执行命令。如 sed '/hello/ p' test.txt只会打印出包含hello的行。 sed '/hello/, /world/ p' test.txt 打印两者之间的所有行。

特殊情况下也可以将文本过滤和行号结合使用, sed '/hello/,+5 p' test.txt 打印第一次出现hello的下面5行

命令

p 复制

复制模式空间中的内容,如果不和 -n参数连用,每一行都会在屏幕输出两次,一行正常输出一行复制,结合 -n 参数后就可以打印需要的内容。

d 删除

没什么可以说的,支持按照行号或者匹配来删除。

i 插入

有的时候一个结果文件没有header,使用sed 可以轻松完成。在匹配位置之前插入内容。

  1. sed '1i name\tlength\foldchange' test.txt

a 追加

和插入命令的区别在于在匹配位置后一行插入内容,,如果想在末尾插入一行信息时将$作为地址。

  1. sed '$a auther:zhaofei' test.txt

c 行替换

有了行的删除插入和追加自然也就会有行替换。

  1. sed '$c auther:zhaofei' test.txt

y 字符转换

sed中的y命令可以实现一一映射的字符替换(注意和s命令的区别)。

  1. [address]y/inchars/outchars/

  2. # inchars中的第一个字符会被转换为outchars中的第一个字符,第二个字符会被转换成outchars中的第二个字符

  3. # 直持续到处理完指定字符。如果inchars和outchars的长度不同会报错

l 输出隐藏字符

类似与cat -A,但是显示隐藏字符形式不同。

w 写入新文件

增强版的cp,只复制自己想要的东西,也可以将一个文件按不同的筛选条件分开保存。

  1. sed -n -e '/a/ w a.txt' -e '1,10 w b.txt' test.txt

  2. sed '1,10d;w new.txt' test.txt

r 读取文件

如果现在a文件的某个地方插入b文件,如在第三行插入

  1. sed '3r b.txt' a.txt

e 执行外部命令

首先要区别于参数-e,这个e是在''里面的命令

  1. sed 'e echo "hello"' test.txt

i 反向执行

在命令前加!反向执行命令

  1. sed '/hello/!d' test.txt

  2. #效果和下面的命令一致

  3. sed -n '/hello/p' test.txt

n 匹配行下移一行操作

提前读取当前行的下一行内容,并且覆盖当前模式空间中的行

  1. seq 5 |sed '3{n;d}'

  2. # 首先匹配到第三行,然后移动到第四行进行删除

  3. # 所及结果是

  4. 1

  5. 2

  6. 3

  7. 5

  8. seq 5 |sed 'n;d' #效果类似与输出奇数行

  9. seq 5 |sed -n 'n;p' #效果类似与输出偶数行

= 打印行号

  1. sed '/hello/!d;=' test.txt

s 替换

通用写法 [address1[,address2]]s/pattern/replacement/[flags]

这里pattern部分支持正则匹配,flags包括n(替换第n个匹配项),g(全局替换),p(输出改变的行,结合-n),i(忽略大小写匹配),w(保存改变的行到新文件)。

如果要替换的的内容包括了 /,第一种方式是使用 \/进行转义,第二种方法是使用 @ | ! ^作为分隔符。

有时候我们会对文件中的目录进行替换,可以下面的写法

  1. pwd |sed 's@/home/zhaofei@/home/feizhao@'

  2. pwd |sed 's^/home/zhaofei^/home/feizhao^'

  3. pwd |sed 's|/home/zhaofei|/home/feizhao|'

pattern支持各种正则表示法,例如

  1. ^ 行首

  2. $ 行尾

  3. . 换行符之外的任意单个字符

  4. ? 匹配之前项0次或者一次

  5. + 匹配1次或者多次

  6. * 匹配0次或者多次

  7. {n} 匹配n

  8. {n,} 匹配至少n

  9. {m,n} 至少m,最多n

  10. [] 匹配任意一个

  11. [-] 匹配范围中的一个

  12. [^] 排除字符

  13. | 或者

  14. # posix字符类

  15. [:alnum:] 字母数字

  16. [:alpha:] 字母

  17. [:blank:] 空格制表符

  18. [:digit:] 数字

  19. [:lower:] 小写字母

  20. [:upper:] 大写字母

  21. [:punct:] 标点

  22. [:space:] 所有空白符(换行符和回车)

  23. # 元字符

  24. \s 单个空白

  25. \w 单词

在进行匹配替换时,我们有时候并不想删除匹配的内容,只是希望其以另一种形式和替换内容一起出现。在sed中,特殊字符 &用来存储匹配模式中的内容。

例如

  1. sed 's/[[:digit:]]/number = &/ test.txt

sed 单行命令 可以完全替代上面所有的命令。
  1. # 删除空行

  2. sed '/^$/d'

  3. #每行后增加空行

  4. sed G

  5. # 在每5行后增加一空白行

  6. gsed '0~5G'

  7. # 在匹配式样“regex”的行之后插入一空行

  8. sed '/regex/G'

  9. # 在匹配式样“regex”的行之前和之后各插入一空行

  10. sed '/regex/{x;p;x;G;}'

  11. # 过滤所有的html标签

  12. sed 's/<[^>]*>//g ; /^$/d' html.txt

  13. # 代替 cat 功能

  14. sed ''

  15. # 代替 head 功能

  16. sed '10 q'

  17. # Dos2unix

  18. sed 's/^M$//'

  19. # Unix2dos

  20. sed 's/$/\r/'

  21. # nl(添加行号)

  22. # sed行号会独占一行

  23. sed = input.file | sed 'N;s/\n/\t/'

  24. # tee

  25. sed n 'p; w new.txt'

  26. # 代替 grep 功能

  27. sed n '/pattern/p'

  28. # grep -v

  29. sed n '/pattern/p!'

  30. # 计算行数

  31. sed -n '$='

  32. # 多个内容同时替换

  33. sed 's/a\|b\|c/d/' tmp.txt

  34. # 将每两行连接成一行

  35. sed '$!N;s/\n/ /'

  36. # 如果当前行以等号开头,将当前行并到上一行末尾

  37. # 并以单个空格代替原来行头的“=”

  38. sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D'

  39. # 显示包含“AAA”、“BBB”或“CCC”的行(任意次序)

  40. sed '/AAA/!d; /BBB/!d; /CCC/!d'

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多