Linux运维笔记-日常操作命令总结(3)

 

使用"whois"命令可以查询到域名的注册信息

1)比如查询www.kevin.com、www.qq.com域名注册信息(使用whois命令查询时,需要去掉域名前面的www)
[root@bastion ~]# whois kevin.com
[root@bastion ~]# whois qq.com

2)查询ip注册信息
[root@bastion ~]# whois 112.110.116.15

"syntax error: unexpected end of file"
一般从windows下的shell脚本传到Linux上可能会出现这样的问题,是因为Windows和Linux下的行末结束符是不一样的。即windoes下的dos格式文件传输到unix系统时,会在每行的结尾多一个^M,也就是说dos文件中的换行符"\r\n"会被转换为unix文件中的换行符"\n",而此文件若是一个可执行文件的话,会导致此文件不能被执行。

=======================================================================================================================
案例一:
比如:我有一个test.sh脚本需要上传到centos系统中执行,但是传输到centos系统中,无法正常执行(前提脚本是完全可以执行的,没有错误)。可能原因是在windos系统上使用了类似notepad++的工具修改了可执行文件内容,导致在centos系统下无法正常执行。

案例二:
在本机(win10)测试正常的程序到了线上linux环境下就是跑步起来,tomcat总是卡在loading config.properties这里,换了一个tomcat也是这种情况,以前是没有问题的。最后怀疑是config.properties文件的问题,然后通过vim查看config.properties文件的fileformat格式,命令":set fileformat",结果显示的是dos, 最后通过命令修改为":set fileformat=unix"

=======================================================================================================================
这样先弄清楚一下"回车"和"换行符"的区别:
1)回车"\r"
本义是光标重新回到本行开头,r的英文return,控制字符可以写成CR,即Carriage Return
2)换行"\n"
本义是光标往下一行(不一定到下一行行首),n的英文newline,控制字符可以写成LF,即Line Feed

解决办法:
1)使用vim打开file.sh脚本文件,进入编辑模式,修改如下:
:set ff=unix (或者:set fileformat=unix)  
:wq  

2)如果以上步骤要求在一个shell批处理文件中完成,那么该怎么办?可以这样:
vi +':w ++ff=unix' +':q' ${file} 

这样一条命令就可以搞定了,但是要严格注意上面空格的位置,不能多不能少。

================================================================================
总结:在windows下新建的sh文件,copy到linux下有的会报错,一般是格式问题。

解决办法:使用vim编辑器进行一下文件格式fileformat转换可使用fileformat或简写ff。
在vim编辑可执行文件:
set ff 或 set ff?                      #显示当前文件格式
set fileformat=unix 或 set ff=unix     #设置成unix格式
set ff=dos                             #设置成dos格式

dos格式文件传输到unix系统时,会在每行的结尾多一个^M(/r)
删除^M的方法: 
:%s//r//g
%s/\r//g

sed文本操作命令使用

sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换、删除、新增、选取等特定工作。

sed命令行格式为:
sed [-nefri] ‘command’ 输入文本

常用选项:
-n∶使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN的资料一般都会被列出到萤幕上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。
-e∶直接在指令列模式上进行 sed 的动作编辑;
-f∶直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的sed 动作;
-r∶sed 的动作支援的是延伸型正规表示法的语法。(预设是基础正规表示法语法)
-i∶直接修改读取的档案内容,而不是由萤幕输出。kevin.txt  

常用命令:
a   ∶新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
c   ∶取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d   ∶删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
i   ∶插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p  ∶列印,亦即将某个选择的资料印出。通常 p 会与参数 sed -n 一起运作~
s  ∶取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!

替换一行中的某部分。s后面的替换符号可以使用/,#,_三种符号
格式:sed 's/要替换的字符串/新的字符串/g'   (要替换的字符串可以用正则表达式)
[root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's/ruby/bird/g'    #替换ruby为bird
[root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's#ruby#bird#g'    #替换ruby为bird
[root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's_ruby_bird_g'    #替换ruby为bird

定址
定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。
如果没有指定地址,sed将处理输入文件的所有行。
地址是一个数字,则表示行号;是“$"符号,则表示最后一行。例如: 
[root@kevin ~]# sed -n '3p' datafile
只打印第三行

只显示指定行范围的文件内容,例如只查看文件的第100行到第200行
[root@kevin ~]# sed -n '100,200p' mysql_slow_query.log

地址是逗号分隔的,那么需要处理的地址是这两行之间的范围(包括这两行在内)。范围可以用数字、正则表达式、或二者的组合表示。
[root@kevin ~]# sed '2,5d' datafile
删除第二到第五行

[root@kevin ~]# sed '/My/,/You/d' datafile
删除包含"My"的行到包含"You"的行之间的行

[root@kevin ~]# sed '/My/,10d' datafile
删除包含"My"的行到第十行的内容
 

示例说明
kevin.txt删除某行
[root@kevin ~]# sed '1d' kevin.txtkevin.txt    #删除第一行 
[root@kevin ~]# sed '$d' kevin.txtkevin.txt     #删除最后一行
[root@kevin ~]# sed '1,2d' kevin.txt   #删除第一行到第二行
[root@kevin ~]# sed '2,$d' kevin.txt   #删除第二行到最后一行

显示某行
[root@kevin ~]# sed -n '1p' kevin.txt   #显示第一行 
[root@kevin ~]# sed -n '$p' kevin.txt   #显示最后一行
[root@kevin ~]# sed -n '1,2p' kevin.txt    #显示第一行到第二行
[root@kevin ~]# sed -n '2,$p' kevin.txt     #显示第二行到最后一行

使用模式进行查询
[root@kevin ~]# sed -n '/ruby/p' kevin.txt    #查询包括关键字ruby所在所有行
[root@kevin ~]# sed -n '/\$/p' kevin.txt      #查询包括关键字$所在所有行,使用反斜线\屏蔽特殊含义

增加一行或多行字符串
[root@kevin ~]# cat kevin.txt
kevin.txtHello!
kevin.txtruby is me,welcome to my blog.
kevin.txtend

[root@kevin ~]# sed '1a drink tea' kevin.txt  #第一行后增加字符串"drink tea"
kevin.txtHello!
kevin.txtdrink tea
kevin.txtruby is me,welcome to my blog. 
kevin.txtend

[root@kevin ~]# sed '1,3a drink tea' kevin.txt #第一行到第三行后增加字符串"drink tea"
kevin.txtHello!
kevin.txtdrink tea
kevin.txtruby is me,welcome to my blog.
kevin.txtdrink tea
kevin.txtend
kevin.txtdrink tea

[root@kevin ~]# sed '1a drink tea\nor coffee' kevin.txt   #第一行后增加多行,使用换行符\n
kevin.txtHello!
kevin.txtdrink tea
kevin.txtor coffee
kevin.txtruby is me,welcome to my blog.
kevin.txtend

代替一行或多行
[root@kevin ~]# sed '1c Hi' kevin.txt#第一行代替为Hi
kevin.txtHi
kevin.txtruby is me,welcome to my blog.
kevin.txtend

[root@kevin ~]# sed '1,2c Hi' kevin.txtkevin.txt#第一行到第二行代替为Hi
kevin.txtHi
kevin.txtend

替换一行中的某部分
格式:sed 's/要替换的字符串/新的字符串/g'   (要替换的字符串可以用正则表达式)
[root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's/ruby/bird/g'       #替换ruby为bird
 [root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's/ruby//g'    #删除ruby

kevin.txt插入
[root@kevin ~]# sed -i '$a bye' kevin.txt     #在文件kevin.txt中最后一行直接输入"bye"
[root@kevin ~]# cat kevin.txt
kevin.txtHello!
kevin.txtruby is me,welcome to my blog.
kevin.txtend
kevin.txtbye

替换:
-e是编辑命令,用于sed执行多个编辑任务的情况下。在下一行开始编辑前,所有的编辑动作将应用到模式缓冲区中的行上。

[root@kevin ~]# sed -e '1,10d' -e 's/My/Your/g' datafile
选项-e用于进行多重编辑。
第一重编辑删除第1-3行。
第二重编辑将出现的所有My替换为Your。
因为是逐行进行这两项编辑(即这两个命令都在模式空间的当前行上执行),所以编辑命令的顺序会影响结果。
 
替换两个或多个空格为一个空格
[root@kevin ~]# sed 's/[ ][ ]*/ /g' file_name

替换两个或多个空格为分隔符:
[root@kevin ~]# sed 's/[ ][ ]*/:/g' file_name
    
如果空格与tkevin.txt共存时用下面的命令进行替换
替换成空格
[root@kevin ~]# sed 's/[[:space:]][[:space:]]*/ /g' filename

替换成分隔符:
[root@kevin ~]# sed 's/[[:space:]][[:space:]]*/:/g' filename

=======================================
sed命令的调用:
在命令行键入命令;将sed命令插入脚本文件,然后调用sed;将sed命令插入脚本文件,并使sed脚本可执行
sed [option] sed命令 输入文件            在命令行使用sed命令,实际命令要加单引号
sed [option] -f sed脚本文件 输入文件     使用sed脚本文件
sed脚本文件 [option] 输入文件            第一行具有sed命令解释器的sed脚本文件

option如下:
n 不打印; sed不写编辑行到标准输出,缺省为打印所有行(编辑和未编辑),p命令可以用来打印编辑行
c 下一命令是编辑命令,使用多项编辑时加入此选项
f 如果正在调用sed脚本文件,使用此选项,此选项通知sed一个脚本文件支持所用的sed命令,如
# sed -f myscript.sed input_file      这里myscript.sed即为支持sed命令的文件

使用重定向文件即可保存sed的输出
 
使用sed在文本中定位文本的方式:
x       x为一行号,比如1
x,y     表示行号范围从x到y,如2,5表示从第2行到第5行
/pattern/    查询包含模式的行,如/disk/或/[a-z]/
/pattern/pattern/   查询包含两个模式的行,如/disk/disks/
/pattern/,x  在给定行号上查询包含模式的行,如/disk/,3
x,/pattern/  通过行号和模式查询匹配行,如 3,/disk/
x,y!    查询不包含指定行号x和y的行
 
基本sed编辑命令:
p      打印匹配行                      c/    用新文本替换定位文本
=      显示文件行号                    s     使用替换模式替换相应模式
a/     在定位行号后附加新文本信息        r     从另一个文本中读文本
i/     在定位行号后插入新文本信息        w     写文本到一个文件
d      删除定位行                      q     第一个模式匹配完成后退出或立即退出
l      显示与八进制ASCII代码等价的控制字符        y  传送字符
n      从另一个文本中读文本下一行,并附加在下一行   {}     在定位行执行的命令组
g      将模式2粘贴到/pattern n/
 
基本sed编程举例:
使用p(rint)显示行: sed -n '2p' temp.txt   只显示第2行,使用选项n
打印范围:  sed -n '1,3p' temp.txt         打印第1行到第3行
打印模式:  sed -n '/movie/'p temp.txt     打印含movie的行
使用模式和行号查询:  sed -n '3,/movie/'p temp.txt   只在第3行查找movie并打印
显示整个文件:  sed -n '1,$'p temp.txt      $为最后一行
任意字符:  sed -n '/.*ing/'p temp.txt     注意是.*ing,而不是*ing
打印行号:  sed -e '/music/=' temp.txt

附加文本:(创建sed脚本文件)chmod u+x script.sed,运行时./script.sed temp.txt
        #!/bin/sed -f
        /name1/ a/             #a/表示此处换行添加文本
        HERE ADD NEW LINE.     #添加的文本内容
插入文本: /name1/ a/ 改成 4 i/ 4表示行号,i插入
修改文本: /name1/ a/ 改成 /name1/ c/ 将修改整行,c修改
删除文本: sed '1d' temp.txt  或者 sed '1,4d' temp.txt
替换文本: sed 's/source/OKSTR/' temp.txt     将source替换成OKSTR
             sed 's//$//g' temp.txt             将文本中所有的$符号全部删除
             sed 's/source/OKSTR/w temp2.txt' temp.txt 将替换后的记录写入文件temp2.txt
替换修改字符串: sed 's/source/"ADD BEFORE" &/p' temp.txt
             结果将在source字符串前面加上"ADD BEFORE",这里的&表示找到的source字符并保存
sed结果写入到文件: sed '1,2 w temp2.txt' temp.txt
                     sed '/name/ w temp2.txt' temp.txt
从文件中读文本: sed '/name/r temp2.txt' temp.txt
在每列最后加文本: sed 's/[0-9]*/& Pass/g' temp.txt
从shell向sed传值: echo $NAME | sed "s/go/$REP/g"   注意需要使用双引号
 
快速一行命令:
's//.$//g'         删除以句点结尾行
'-e /abcd/d'       删除包含abcd的行
's/[][][]*/[]/g'   删除一个以上空格,用一个空格代替
's/^[][]*//g'      删除行首空格
's//.[][]*/[]/g'   删除句号后跟两个或更多的空格,用一个空格代替
'/^$/d'            删除空行
's/^.//g'          删除第一个字符,区别  's//.//g'删除所有的句点
's/COL/(.../)//g'  删除紧跟COL的后三个字母
's/^////g'         删除路径中第一个/
 
=================================================
1)使用句点匹配单字符    
句点“.”可以匹配任意单字符。“.”可以匹配字符串头,也可以是中间任意字符。假定正在过滤一个文本文件,对于一个有1 0个字符的脚本集,要求前4个字符之后为X C,匹配操作如下:. . . .X C. . . .

2)在行首以^匹配字符串或字符序列    
^只允许在一行的开始匹配字符或单词。在行首第4个字符为1,匹配操作表示为:^ . . . 1

3)在行尾以$匹配字符串或字符    
可以说$与^正相反,它在行尾匹配字符串或字符, $符号放在匹配单词后。如果在行尾匹配单词j e t 0 1,操作如下:j e t 0 1 $    如果只返回包含一个字符的行,操作如下:^ . $

4)使用*匹配字符串中的单字符或其重复序列    
使用此特殊字符匹配任意字符或字符串的重复多次表达式。

5)使用/屏蔽一个特殊字符的含义    有
时需要查找一些字符或字符串,而它们包含了系统指定为特殊字符的一个字符。如果要在正则表达式中匹配以* . p a s结尾的所有文件,可做如下操作:/ * / . p a s

6)使用[]匹配一个范围或集合     
使用[ ]匹配特定字符串或字符串集,可以用逗号将括弧内要匹配的不同字符串分开,但并不强制要求这样做(一些系统提倡在复杂的表达式中使用逗号),
这样做可以增 加模式的可读性。使用“ -”表示一个字符串范围,表明字符串范围从“ -”左边字符开始,到“ -”右边字符结束。假定要匹配任意一个数字,
可以使用:[ 0 1 2 3 4 5 6 7 8 9 ]    要匹配任意字母,则使用:[ A - Z a - z ]表明从A - Z、a - z的字母范围。

7)使用/{/}匹配模式结果出现的次数    
使用*可匹配所有匹配结果任意次,但如果只要指定次数,就应使用/ { / },此模式有三种形式,即:
pattern/{n/} 匹配模式出现n次。
pattern/{n,/} 匹配模式出现最少n次。
pattern/{n,m} 匹配模式出现n到m次之间,n , m为0 - 2 5 5中任意整数。
匹配字母A出现两次,并以B结尾,操作如下:A / { 2 / } B匹配值为A A B    匹配A至少4次,使用:A / { 4 , / } B
  
======================
替换单引号为空,可以这样写:
sed 's/'"'"'//g'
sed 's/'\''//g'
sed s/\'//g
 
=====================
在文件的第一行前面插入一行abc
sed -i '1i\abc' urfile

awk命令使用

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,
以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。

awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: 
AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、
对输入执行计算以及生成报表,还有无数其他的功能。

使用方法
awk '{pattern + action}' {filenames}

尽管操作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。
花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 pattern就是要表示的正则表达式,用斜杠括起来。

awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本
文件中的信息。
通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。

调用awk
有三种方式调用awk
1)命令行方式
awk [-F  field-separator]  'commands'  input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。

2)shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk

3)将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。


假设last -n 5的输出如下:
[root@kevin ~]# last -n 5 <==仅取出前五行
root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in
root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)
root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)
dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)
root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)

如果只是显示最近登录的5个帐号
[root@kevin ~]# last -n 5 | awk  '{print $1}'
root
root
root
dmtsai
root

awk工作流程是这样的:
读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。
默认域分隔符是"空白键" 或 "[tab]键",所以$1表示登录用户,$3表示登录用户ip,以此类推。

如果只是显示/etc/passwd的账户
[root@kevin ~]# cat /etc/passwd |awk  -F ':'  '{print $1}'  
root
daemon
bin
sys

这种是awk+action的示例,每行都会执行action{print $1}。
-F指定域分隔符为':'。

如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以tab键分割
[root@kevin ~]# cat /etc/passwd |awk  -F ':'  '{print $1"\t"$7}'
root    /bin/bash
daemon  /bin/sh
bin     /bin/sh
sys     /bin/sh
 
如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"。

[root@kevin ~]# cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
name,shell
root,/bin/bash
daemon,/bin/sh
bin,/bin/sh
sys,/bin/sh
....
blue,/bin/nosh

awk工作流程是这样的:
先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,
$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。

搜索/etc/passwd有root关键字的所有行
[root@kevin ~]# awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。

搜索支持正则,例如找root开头的: awk -F: '/^root/' /etc/passwd

搜索/etc/passwd有root关键字的所有行,并显示对应的shell
[root@kevin ~]# awk -F: '/root/{print $7}' /etc/passwd             
/bin/bash

这里指定了action{print $7}

awk内置变量
awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。

ARGC               命令行参数个数
ARGV               命令行参数排列
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                浏览文件的记录数
FS                 设置输入域分隔符,等价于命令行 -F选项
NF                 浏览记录的域的个数
NR                 已读的记录数
OFS                输出域分隔符
ORS                输出记录分隔符
RS                 控制记录分隔符

此外,$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。

统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
[root@kevin ~]# awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh
filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh
filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh
 
使用printf替代print,可以让代码更加简洁,易读
[root@kevin ~]# awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
 
print和printf
awk中同时提供了print和printf两种打印输出的函数。

其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。
这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。

printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。

awk编程:变量和赋值
除了awk的内置变量,awk还可以自定义变量。

下面统计/etc/passwd的账户人数
[root@kevin ~]# awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
......
user count is  40

count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开。

这里没有初始化count,虽然默认是0,但是妥当的做法还是初始化为0:
[root@kevin ~]# awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd
[start]user count is  0
root:x:0:0:root:/root:/bin/bash
...
[end]user count is  40
 
统计某个文件夹下的文件占用的字节数
[root@kevin ~]# ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
[end]size is  8657198
 
如果以M为单位显示:
[root@kevin ~]# ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}' 
[end]size is  8.25889 M

注意,统计不包括文件夹的子目录。

条件语句
awk中的条件语句是从C语言中借鉴来的,见如下声明方式:
if (expression) {
    statement;
    statement;
    ... ...
}

if (expression) {
    statement;
} else {
    statement2;
}

if (expression) {
    statement1;
} else if (expression1) {
    statement2;
} else {
    statement3;
}

统计某个文件夹下的文件占用的字节数,过滤4096大小的文件(一般都是文件夹):
[root@kevin ~]# ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'
[start]size is  0
[end]size is  0.0610514 M

循环语句
awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。

数组
因为awk中数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。值和关键字都存储在内部的一张针对key/value应用hash的表格里。
由于hash不是顺序存储,因此在显示数组内容时会发现,它们并不是按照你预料的顺序显示出来的。数组和变量一样,都是在使用时自动创建的,awk
也同样会自动判断其存储的是数字还是字符串。一般而言,awk中的数组用来从记录中收集信息,可以用于计算总和、统计单词以及跟踪模板被匹配的次数等。

显示/etc/passwd的账户
[root@kevin ~]# awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
0 root
1 daemon
2 bin
3 sys
4 sync
5 games
......

这里使用for循环遍历数组

grep命令:从文件中查找匹配模式的行

1.作用
Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

2.格式
grep [options]

3.主要参数
[options]主要参数:
-c:只输出匹配行的计数。
-I:不区分大 小写(只适用于单字符)。
-h:查询多文件时不显示文件名。
-l:查询多文件时只输出包含匹配字符的文件名。
-n:显示匹配行及 行号。
-s:不显示不存在或无匹配文本的错误信息。
-v:显示不包含匹配文本的所有行。

pattern正则表达式主要参数:
\: 忽略正则表达式中特殊字符的原有含义。
^:匹配正则表达式的开始行。
$: 匹配正则表达式的结束行。
\<:从匹配正则表达 式的行开始。
\>:到匹配正则表达式的行结束。
[ ]:单个字符,如[A]即A符合要求 。
[ - ]:范围,如[A-Z],即A、B、C一直到Z都符合要求 。
。:所有的单个字符。
* :有字符,长度可以为0。

grep -v 过滤
grep -c 打印关键字符所在的行数
grep -An  打印关键字符所在的行的后n行内容
grep -Bn  打印关键字符所在的行的前n行内容
grep -Cn  打印关键字符所在的行的前后各n行内容

cat filename |grep "abc"
fgrep -R "abc" ./*

4.grep命令使用简单实例
[root@kevin ~]# grep ‘test’ d*
显示所有以d开头的文件中包含 test的行。

[root@kevin ~]# grep ‘test’ aa bb cc
显示在aa,bb,cc文件中匹配test的行。

[root@kevin ~]# grep ‘[a-z]\{5\}’ aa
显示所有包含每个字符串至少有5个连续小写字符的字符串的行。

[root@kevin ~]# grep ‘w\(es\)t.*\1′ aa
如果west被匹配,则es就被存储到内存中,并标记为1,然后搜索任意个字符(.*),这些字符后面紧跟着 另外一个es(\1),找到就显示该行。
如果用egrep或grep -E,就不用”\”号进行转义,直接写成’w(es)t.*\1′就可以了。

5.grep命令使用复杂实例
假设您正在’/usr/src/Linux/Doc’目录下搜索带字符 串’magic’的文件:
[root@kevin ~]# grep magic /usr/src/Linux/Doc/*
sysrq.txt:* How do I enable the magic SysRQ key?
sysrq.txt:* How do I use the magic SysRQ key?

其中文件’sysrp.txt’包含该字符串,讨论的是 SysRQ 的功能。

默认情况下,’grep’只搜索当前目录。如果 此目录下有许多子目录,’grep’会以如下形式列出:
grep: sound: Is a directory

这可能会使’grep’ 的输出难于阅读。这里有两种解决的办法:
明确要求搜索子目录:grep -r
或忽略子目录:grep -d skip

如果有很多 输出时,您可以通过管道将其转到’less’上阅读:
[root@kevin ~]# grep magic /usr/src/Linux/Documentation/* | less
这样,您就可以更方便地阅读。

有一点要注意,
您必需提供一个文件过滤方式(搜索全部文件的话用 *)。如果您忘了,’grep’会一直等着,直到该程序被中断。
如果您遇到了这样的情况,按 <CTRL c> ,然后再试。

下面还有一些有意思的命令行参数:
grep -i pattern files :不区分大小写地搜索。默认情况区分大小写,
grep -l pattern files :只列出匹配的文件名,
grep -L pattern files :列出不匹配的文件名,
grep -w pattern files :只匹配整个单词,而不是字符串的一部分(如匹配’magic’,而不是’magical’),
grep -C number pattern files :匹配的上下文分别显示[number]行,
grep pattern1 | pattern2 files :显示匹配 pattern1 或 pattern2 的行,
grep pattern1 files | grep pattern2 :显示既匹配 pattern1 又匹配 pattern2 的行。

grep -n pattern files  即可显示行号信息
grep -c pattern files  即可查找总行数

这里还有些用于搜索的特殊符号:
\< 和 \> 分别标注单词的开始与结尾。
例如:
grep man * 会匹配 ‘Batman’、’manic’、’man’等,
grep ‘\<man’ * 匹配’manic’和’man’,但不是’Batman’,
grep ‘\<man\>’ 只匹配’man’,而不是’Batman’或’manic’等其他的字符串。
‘^’:指匹配的字符串在行首,
‘$’:指匹配的字符串在行 尾,

==============grep、fgrep、egrep的区别=================
者都是搜索工具,但功能上有区别。
1)首先,grep支持的是标准正则表达式。
2)fgrep,不支持正则表达式,只用于匹配固定字符串。
grep把模式当做正则表达式看,fgrep把模式当做固定字符串看,所以后者要比前者速度快,当然同时后者的搜索功能要弱于前者。
3)egrep:为grep 的扩充版本, 改良了许多传统 grep 不能或不便的操作. 比如:
- grep 之下不支持 ? 与 + 这两种 modifier, 但 egrep 则可。
- grep 不支持 a|b 或 (abc|xyz) 这类"或一"比对, 但 egrep 则可。
- grep 在处理 {n,m} 时, 需用 \{ 与 \} 处理, 但 egrep 则不需。

===========================================
示例说明
[root@kevin ~]# ps -ef | grep in.telnetd 
root 19955 181 0 13:43:53 ? 0:00 in.telnetd 

[root@kevin ~]# more size.txt size文件的内容 
b124230 
b034325 
a081016 
m7187998 
m7282064 
a022021 
a061048 
m9324822 
b103303 
a013386 
b044525 
m8987131 
B081016 
M45678 
B103303 
BADc2345 

[root@kevin ~]# more size.txt | grep '[a-b]' 范围 ;如[A-Z]即A,B,C一直到Z都符合要求 
b124230 
b034325 
a081016 
a022021 
a061048 
b103303 
a013386 
b044525 

[root@kevin ~]# more size.txt | grep '[a-b]'* 
b124230 
b034325 
a081016 
m7187998 
m7282064 
a022021 
a061048 
m9324822 
b103303 
a013386 
b044525 
m8987131 
B081016 
M45678 
B103303 
BADc2345 

[root@kevin ~]# more size.txt | grep 'b'    #单个字符;如[b] 即b符合要求 
b124230 
b034325 
b103303 
b044525 

[root@kevin ~]# more size.txt | grep '[bB]'  #b或者B
b124230 
b034325 
b103303 
b044525 
B081016 
B103303 
BADc2345 

[root@kevin ~]# grep 'root' /etc/group 
root::0:root 
bin::2:root,bin,daemon 
sys::3:root,bin,sys,adm 
adm::4:root,adm,daemon 
uucp::5:root,uucp 
mail::6:root 
tty::7:root,tty,adm 
lp::8:root,lp,adm 
nuucp::9:root,nuucp 
daemon::12:root,daemon 

[root@kevin ~]# grep '^root' /etc/group      #匹配正则表达式的开始行 
root::0:root 

[root@kevin ~]# grep 'uucp' /etc/group 
uucp::5:root,uucp 
nuucp::9:root,nuucp 

[root@kevin ~]# grep '\<uucp' /etc/group 
uucp::5:root,uucp 

[root@kevin ~]# grep 'root[root@kevin ~]#' /etc/group       #匹配正则表达式的结束行 
root::0:root 
mail::6:root 

[root@kevin ~]# more size.txt | grep -i 'b1..*3'   #忽略大小写 
b124230 
b103303 
B103303 

[root@kevin ~]# more size.txt | grep -iv 'b1..*3'   #查找不包含匹配项的行 
b034325 
a081016 
m7187998 
m7282064 
a022021 
a061048 
m9324822 
a013386 
b044525 
m8987131 
B081016 
M45678 
BADc2345 

[root@kevin ~]# more size.txt | grep -in 'b1..*3' 
1:b124230 
9:b103303 
15:B103303 

[root@kevin ~]# grep '[root@kevin ~]#' /etc/init.d/nfs.server | wc -l 
128 

[root@kevin ~]# grep '\[root@kevin ~]#' /etc/init.d/nfs.server | wc –l      #忽略正则表达式中特殊字符的原有含义 
15 

[root@kevin ~]# grep '\$' /etc/init.d/nfs.server
case "$1" in
>/tmp/sharetab.$$
[ "x$fstype" != xnfs ] &&
echo "$path\t$res\t$fstype\t$opts\t$desc"
>>/tmp/sharetab.$$
/usr/bin/touch -r /etc/dfs/sharetab /tmp/sharetab.$$
/usr/bin/mv -f /tmp/sharetab.$$ /etc/dfs/sharetab
if [ -f /etc/dfs/dfstab ] && /usr/bin/egrep -v '^[ ]*(#|$)'
if [ $startnfsd -eq 0 -a -f /etc/rmmount.conf ] &&
if [ $startnfsd -ne 0 ]; then
elif [ ! -n "$_INIT_RUN_LEVEL" ]; then
while [ $wtime -gt 0 ]; do
wtime=`expr $wtime - 1`
if [ $wtime -eq 0 ]; then
echo "Usage: $0 { start | stop }"
 
[root@kevin ~]# more size.txt
the test file
their are files
The end
 
[root@kevin ~]# grep 'the' size.txt
the test file
their are files
 
[root@kevin ~]# grep '\<the' size.txt
the test file
their are files
 
[root@kevin ~]# grep 'the\>' size.txt
the test file
 
[root@kevin ~]# grep '\<the\>' size.txt
the test file
 
[root@kevin ~]# grep '\<[Tt]he\>' size.txt
the test file
 

多个文件查询
[root@kevin ~]# grep "sort" *.txt       #见文件名的匹配
 
行匹配:输出匹配行的计数
[root@kevin ~]# grep -c "48" kevin.txt   #输出文档中含有48字符的行数
 
显示匹配行和行数
[root@kevin ~]# grep -n "48" kevin.txt       #显示所有匹配48的行和行号
 
显示非匹配的行
[root@kevin ~]# grep -vn "48" kevin.txt      #输出所有不包含48的行
 
显示非匹配的行
[root@kevin ~]# grep -vn "48" kevin.txt      #输出所有不包含48的行
 
大小写敏感
[root@kevin ~]# grep -i "ab" kevin.txt       #输出所有含有ab或Ab的字符串的行
 
====================================
正则表达式的应用 (注意:最好把正则表达式用单引号括起来)
[root@kevin ~]# grep '[239].' kevin.txt      #输出所有含有以2,3或9开头的,并且是两个数字的行
 
不匹配测试
[root@kevin ~]# grep '^[^48]' kevin.txt      #不匹配行首是48的行
 
使用扩展模式匹配
[root@kevin ~]# grep -E '219|216' kevin.txt
 
使用类名
可以使用国际模式匹配的类名:
[[:upper:]]   [A-Z]
[[:lower:]]   [a-z]
[[:digit:]]   [0-9]
[[:alnum:]]   [0-9a-zA-Z]
[[:space:]]   空格或tab
[[:alpha:]]   [a-zA-Z]
 
[root@kevin ~]# grep '5[[:upper:]][[:upper:]]' kevin.txt     #查询以5开头以两个大写字母结尾的行

cat、more、less、tail、head命令

cat 是一个文本文件(查看)和(连接)工具,通常与more搭配使用,与more不同的是cat可以合并文件。查看一个文件的内容,用cat比较简单,
就是cat后面直接接文件名。 

cat [选项] [文件]... 
选项 
-A, --show-all           等价于 -vET 
-b, --number-nonblank    对非空输出行编号 
-e                       等价于 -vE 
-E, --show-ends          在每行结束处显示 $ 
-n, --number             对输出的所有行编号 
-s, --squeeze-blank      不输出多行空行 
-t                       与 -vT 等价 
-T, --show-tabs          将跳格字符显示为 ^I 
-u                       (被忽略) 
-v, --show-nonprinting   使用 ^ 和 M- 引用,除了 LFD 和 TAB 之外 
--help     显示此帮助信息并离开 

cat 查看文件内容实例: 
[root@kevin ~]# cat /etc/profile           //查看/etc/目录下的profile文件内容; 
[root@kevin ~]# cat -b /etc/fstab         //查看/etc/目录下的profile内容,并且对非空白行进行编号,行号从1开始; 
[root@kevin ~]# cat -n /etc/profile      //对/etc目录中的profile的所有的行(包括空白行)进行编号输出显示; 
[root@kevin ~]# cat -E /etc/profile      //查看/etc/下的profile内容,并且在每行的结尾处附加$符号; 
  
cat 加参数-n 和nl工具差不多,文件内容输出的同时,都会在每行前面加上行号; 
[root@kevin ~]# cat -n /etc/profile 
[root@kevin ~]# nl /etc/profile 

cat 可以同时显示多个文件的内容,比如我们可以在一个cat命令上同时显示两个文件的内容; 
[root@kevin ~]# cat /etc/fstab /etc/profile 
  
cat 对于内容极大的文件来说,可以通过管道|传送到more 工具,然后一页一页的查看; 
[root@kevin ~]# cat /etc/fstab /etc/profile | more 
  
cat 的创建、连接文件功能实例: 
cat 有创建文件的功能,创建文件后,要以EOF或STOP结束; 

[root@kevin ~]# cat > kevin.txt<< EOF          
> 我来测试 cat 创建文件,并且为文件输入内容;       
> 北京是个好地方;         
> EOF   

[root@kevin ~]# cat kevin.txt
我来测试 cat 创建文件,并且为文件输入内容; 
北京是个好地方; 
  
cat 还有向已存在的文件追加内容的功能; 
[root@kevin ~]# cat grace.txt 
I am BeiNanNanBei From grace.Org .   
我正在为cat命令写文档 

[root@kevin ~]# cat >> grace.txt << EOF   
> 我来测试cat向文档追加内容的功能;       
> OK? 
> OK~ 
> 北京你好 
> EOF    

[root@kevin ~]# cat grace.txt //查看文件内容,看是否追回成功。 
I am BeiNanNanBei From grace.Org . 
我正在为cat命令写文档 
我来测试cat向文档追加内容的功能;   
OK? 
OK~ 
北京你好 

cat 连接多个文件的内容并且输出到一个新文件中; 
假设我们有sir01.txt、sir02.tx和sir03.txt ,并且内容如下; 

[root@kevin ~]# cat sir01.txt   
123456 
i am testing 

[root@kevin ~]# cat sir02.txt 
56789 
BeiNan Tested 

[root@kevin ~]# cat sir03.txt 
09876 
grace.org testing 
  
我想通过cat 把sir01.txt、sir02.txt及sir03.txt 三个文件连接在一起(也就是说把这三个文件的内容都接在一起)并输出到一个新的文件sir04.txt 中。 

注意:
其原理是把三个文件的内容连接起来,然后创建sir04.txt文件,并且把几个文件的内容同时写入sir04.txt中。特别值得一提的是,如果您输入到一个已经
存在的sir04.txt 文件,会把sir04.txt内容清空。 

[root@kevin ~]# cat sir01.txt sir02.txt sir03.txt > sir04.txt 
[root@kevin ~]# more sir04.txt 
123456 
i am testing 
56789 
BeiNan Tested 
09876 
grace.org testing 
  
cat 把一个或多个已存在的文件内容,追加到一个已存在的文件中 
[root@kevin ~]# cat sir00.txt 
grace.org forever 

[root@kevin ~]# cat sir01.txt sir02.txt sir03.txt >> sir00.txt 

[root@kevin ~]# cat sir00.txt 
grace.org forever 
123456 
i am testing 
56789 
BeiNan Tested 
09876 
grace.org testing 
  

======================================================
more 是我们最常用的工具之一,最常用的就是显示输出的内容,然后根据窗口的大小进行分页显示,然后还能提示文件的百分比; 

参数如下: 
+num   从第num行开始显示; 
-num   定义屏幕大小,为num行; 
+/pattern   从pattern 前两行开始显示; 
-c   从顶部清屏然后显示; 
-d   提示Press space to continue, 'q' to quit.(按空格键继续,按q键退出),禁用响铃功能; 
-l    忽略Ctrl+l (换页)字符; 
-p    通过清除窗口而不是滚屏来对文件进行换页。和-c参数有点相似; 
-s    把连续的多个空行显示为一行; 
-u    把文件内容中的下划线去掉退出more的动作指令是q 

more 的参数应用举例: 
[root@kevin ~]# more -dc /etc/profile        //显示提示,并从终端或控制台顶部显示; 
[root@kevin ~]# more +4 /etc/profile         //从profile的第4行开始显示; 
[root@kevin ~]# more -4 /etc/profile          //每屏显示4行; 
[root@kevin ~]# more +/MAIL /etc/profile         //从profile中的第一个MAIL单词的前两行开始显示; 

more 的动作指令: 
我们查看一个内容较大的文件时,要用到more的动作指令,比如ctrl+f(或空格键) 是向下显示一屏,ctrl+b是返回上一屏; Enter键可以向下滚动显示n行,要通过定,默认为1行; 

我们只说几个常用的; 自己尝试一下就知道了; 
Enter       向下n行,需要定义,默认为1行; 
Ctrl+f    向下滚动一屏; 
空格键          向下滚动一屏; 
Ctrl+b  返回上一屏; 
=         输出当前行的行号; 
:f      输出文件名和当前行的行号; 
v      调用vi编辑器; 
! 命令            调用Shell,并执行命令; 
q     退出more当我们查看某一文件时,想调用vi来编辑它,不要忘记了v动作指令,这是比较方便的; 

其它命令通过管道和more结合的运用例子: 
比如我们列一个目录下的文件,由于内容太多,我们应该学会用more来分页显示。这得和管道 | 结合起来,比如:
[root@kevin ~]# ls -l /etc |more 

=======================================================
less 查看文件内容 工具 

less 工具也是对文件或其它输出进行分页显示的工具,应该说是linux正统查看文件内容的工具,功能极其强大;您是初学者,我建议您用less。
由于less的内容太多,我们把最常用的介绍一下; 

常用参数 
-c 从顶部(从上到下)刷新屏幕,并显示文件内容。而不是通过底部滚动完成刷新; 
-f 强制打开文件,二进制文件显示时,不提示警告; 
-i 搜索时忽略大小写;除非搜索串中包含大写字母; 
-I 搜索时忽略大小写,除非搜索串中包含小写字母; 
-m 显示读取文件的百分比; 
-M 显法读取文件的百分比、行号及总行数; 
-N 在每行前输出行号; 
-p pattern 搜索pattern;比如在/etc/profile搜索单词MAIL,就用 less -p MAIL /etc/profile 
-s 把连续多个空白行作为一个空白行显示; 
-Q 在终端下不响铃; 
  
比如:我们在显示/etc/profile的内容时,让其显示行号; 
[root@kevin ~]# less -N   /etc/profile 
  
less的动作命令: 
进入less后,我们得学几个动作,这样更方便 我们查阅文件内容;最应该记住的命令就是q,这个能让less终止查看文件退出; 

动作: 
回车键 向下移动一行; 
y 向上移动一行; 
空格键 向下滚动一屏; 
b 向上滚动一屏; 
d 向下滚动半屏; 
h less的帮助; 
u 向上洋动半屏; 
w 可以指定显示哪行开始显示,是从指定数字的下一行显示;比如指定的是6,那就从第7行显示; 
g 跳到第一行; 
G 跳到最后一行; 
p n% 跳到n%,比如 10%,也就是说比整个文件内容的10%处开始显示; 
/pattern 搜索pattern ,比如 /MAIL表示在文件中搜索MAIL单词; 
v 调用vi编辑器; 
q 退出less 
!command 调用SHELL,可以运行命令;比如!ls 显示当前列当前目录下的所有文件; 
  
就less的动作来说,内容太多了,用的时候查一查man less是最好的。在这里就不举例子了; 

==========================================================
head 工具,显示文件内容的前几行 
head 是显示一个文件的内容的前多少行; 

用法比较简单; 
head -n 行数值 文件名; 

比如我们显示/etc/profile的前10行内容,应该是: 
[root@kevin ~]# head -n 10 /etc/profile 

=========================================================
tail 工具,显示文件内容的最后几行 

tail 是显示一个文件的内容的最后多少行; 

用法比较简单; 
tail   -n 行数值 文件名; 

比如我们显示/etc/profile的最后5行内容,应该是: 
[root@kevin ~]# tail -n 5 /etc/profile 

tail -f /var/log/syslog 显示文件 syslog 的后十行内容并在文件内容增加后,且自动显示新增的文件内容。

cut命令:打印每行特定范围内内容

cut是一个选取命令,就是将一段数据经过分析,取出我们想要的。一般来说,选取信息通常是针对“行”来进行分析的,并不是整篇信息分析的。

其语法格式为:
cut  [-bn] [file] 或 cut [-c] [file]  或  cut [-df] [file]

使用说明
cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。
如果不指定 File 参数,cut 命令将读取标准输入。必须指定 -b、-c 或 -f 标志之一。

主要参数
-b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。
-c :以字符为单位进行分割。
-d :自定义分隔符,默认为制表符。
-f  :与-d一起使用,指定显示哪个区域。
-n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的<br />范围之内,该字符将被写出;否则,该字符将被排除。

cut一般以什么为依据呢? 也就是说,我怎么告诉cut我想定位到的剪切内容呢?
cut命令主要是接受三个定位方法:
第一,字节(bytes),用选项-b
第二,字符(characters),用选项-c
第三,域(fields),用选项-f

=========================================
cut在取列内容的时候和awk相识

awk -F"" '{print $n}'     以-F后的引号内的内容为列的分隔符,打印第n行
cut -d"" -fn              以-d后的引号内的内容为列的分隔符,打印第n行

比如打印a.txt文件中以空格为列的分隔符,打印第5行
awk -F" " '{print $5}' a.txt  当以空格为分隔符的时候,-F" " 可以省去
cut -d" " -f5 a.txt
=========================================

以“字节”定位
举个例子吧,当你执行ps命令时,会输出类似如下的内容:
[root@kevin ~]# who
rocrocket :0           2009-01-08 11:07
rocrocket pts/0        2009-01-08 11:23 (:0.0)
rocrocket pts/1        2009-01-08 14:15 (:0.0)
如果我们想提取每一行的第3个字节,就这样:

[root@kevin ~]# who|cut -b 3
c
c
c

如果“字节”定位中,我想提取第3,第4、第5和第8个字节,怎么办?
-b支持形如3-5的写法,而且多个定位之间用逗号隔开就成了。看看例子吧:
[root@kevin ~]# who|cut -b 3-5,8
croe
croe
croe

但有一点要注意,cut命令如果使用了-b选项,那么执行此命令时,cut会先把-b后面所有的定位进行从小到大排序,然后再提取。
可不能颠倒定位的顺序哦。这个例子就可以说明这个问题:

[root@kevin ~]# who|cut -b 8,3-5
croe
croe
croe

还有哪些类似“3-5”这样的小技巧,列举一下吧!
[root@kevin ~]# who
rocrocket :0           2009-01-08 11:07
rocrocket pts/0        2009-01-08 11:23 (:0.0)
rocrocket pts/1        2009-01-08 14:15 (:0.0)
[root@kevin ~]# who|cut -b -3
roc
roc
roc
[root@kevin ~]# who|cut -b 3-
crocket :0           2009-01-08 11:07
crocket pts/0        2009-01-08 11:23 (:0.0)
crocket pts/1        2009-01-08 14:15 (:0.0)

-3表示从第一个字节到第三个字节,而3-表示从第三个字节到行尾。如果你细心,你可以看到这两种情况下,都包括了第三个字节“c”。
如果我执行who|cut -b -3,3-,你觉得会如何呢?答案是输出整行,不会出现连续两个重叠的c的。看:

[root@kevin ~]# who|cut -b -3,3-
rocrocket :0           2009-01-08 11:07
rocrocket pts/0        2009-01-08 11:23 (:0.0)
rocrocket pts/1        2009-01-08 14:15 (:0.0)

给个以字符为定位标志的最简单的例子吧!
下面例子你似曾相识,提取第3,第4,第5和第8个字符:
[root@kevin ~]# who|cut -c 3-5,8
croe
croe
croe

不过,看着怎么和-b没有什么区别啊?莫非-b和-c作用一样? 其实不然,看似相同,只是因为这个例子举的不好,who输出的都是单字节字符,
所以用-b和-c没有区别,如果你提取中文,区别就看出来了,来,看看中文提取的情况:

[root@kevin ~]# cat cut_ch.txt
星期一
星期二
星期三
星期四
[root@kevin ~]# cut -b 3 cut_ch.txt
�
�
�
�
[root@kevin ~]# cut -c 3 cut_ch.txt
一
二
三
四

看到了吧,用-c则会以字符为单位,输出正常;而-b只会傻傻的以字节(8位二进制位)来计算,输出就是乱码。
既然提到了这个知识点,就再补充一句,如果你学有余力,就提高一下。
当遇到多字节字符时,可以使用-n选项,-n用于告诉cut不要将多字节字符拆开。例子如下:

[root@kevin ~]# cat cut_ch.txt |cut -b 2
�
�
�
�
[root@kevin ~]# cat cut_ch.txt |cut -nb 2

[root@kevin ~]# cat cut_ch.txt |cut -nb 1,2,3
星
星
星
星

域是怎么回事呢?解释解释:)
为什么会有“域”的提取呢,因为刚才提到的-b和-c只能在固定格式的文档中提取信息,而对于非固定格式的信息则束手无策。这时候“域”就派上用场了。
如果你观察过/etc/passwd文件,你会发现,它并不像who的输出信息那样具有固定格式,而是比较零散的排放。但是,冒号在这个文件的每一行中都
起到了非常重要的作用,冒号用来隔开每一个项。

cut命令提供了这样的提取方式,具体的说就是设置“间隔符”,再设置“提取第几个域”,就OK了!

以/etc/passwd的前五行内容为例:
[root@kevin ~]# cat /etc/passwd|head -n 5
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@kevin ~]# cat /etc/passwd|head -n 5|cut -d : -f 1
root
bin
daemon
adm
lp

用-d来设置间隔符为冒号,然后用-f来设置我要取的是第一个域,再按回车,所有的用户名就都列出来了!
当然,在设定-f时,也可以使用例如3-5或者4-类似的格式:

[root@kevin ~]# cat /etc/passwd|head -n 5|cut -d : -f 1,3-5
root:0:0:root
bin:1:1:bin
daemon:2:2:daemon
adm:3:4:adm
lp:4:7:lp
[root@kevin ~]# cat /etc/passwd|head -n 5|cut -d : -f 1,3-5,7
root:0:0:root:/bin/bash
bin:1:1:bin:/sbin/nologin
daemon:2:2:daemon:/sbin/nologin
adm:3:4:adm:/sbin/nologin
lp:4:7:lp:/sbin/nologin
[root@kevin ~]# cat /etc/passwd|head -n 5|cut -d : -f -2
root:x
bin:x
daemon:x
adm:x
lp:x

如果遇到空格和制表符时,怎么分辨呢?我觉得有点乱,怎么办?
有时候制表符确实很难辨认,有一个方法可以看出一段空格到底是由若干个空格组成的还是由一个制表符组成的。
[root@kevin ~]# cat tab_space.txt
this is tab finish.
this is several space      finish.
[root@kevin ~]# sed -n l tab_space.txt
this is tab\tfinish.$
this is several space      finish.$

如果是制表符(TAB),那么会显示为\t符号,如果是空格,就会原样显示。
通过此方法即可以判断制表符和空格了。
注意,上面sed -n后面的字符是L的小写字母哦,不要看错。

我应该在cut -d中用什么符号来设定制表符或空格呢?
其实cut的-d选项的默认间隔符就是制表符,所以当你就是要使用制表符的时候,完全就可以省略-d选项,而直接用-f来取域就可以了。

如果你设定一个空格为间隔符,那么就这样:
[root@kevin ~]# cat tab_space.txt |cut -d ' ' -f 1
this
this

注意,两个单引号之间可确实要有一个空格哦,不能偷懒。
而且,你只能在-d后面设置一个空格,可不许设置多个空格,因为cut只允许间隔符是一个字符。

[root@kevin ~]# cat tab_space.txt |cut -d ' ' -f 1
cut: the delimiter must be a single character
Try `cut --help' for more information.

cut有哪些缺陷和不足?
猜出来了吧?对,就是在处理多空格时。
如果文件里面的某些域是由若干个空格来间隔的,那么用cut就有点麻烦了,因为cut只擅长处理“以一个字符间隔”的文本内容。

tr命令:删除,去重,替换文本内容

可以把tr看作为一个简化的sed工具,tr表示为:translate。tr命令主要用于实现以下两个功能

替换操作的字符串转换。
删除操作的字符串转换,可以很容易的删除一些控制字符或者是空行。
tr命令能够实现的功能,都能够用sed命令来实现。但就具体的替换功能来说,tr用起来更容易,也比较简单。

一,命令格式

tr [option] ["string1"] ["string2"] < file  

常用的选项有:
默认选项。就是没有任何选项的时候,tr默认为替换操作,就是将string1在文件中出现的字符替换为string2中的字符,这里要注意的是替换关系。
-c选项,用string1中字符的补集替换string1,这里的字符集为ASCII。
-d选项,删除文件中所有在string1中出现的字符。
-s选项,删除文件中重复并且在string1中出现的字符,只保留一个。
-c选项在使用时,只是将string1替换为现在的补集

[root@kevin ~]# echo "hello world,root,2012" | tr -c "0-9" "*"  
*****************2012*  

可以看出,我们使用0-9,添加-c选项后,会把0-9替换为其补集,这时补集自然不包含0-9,而包含很多其它的字符,接下来就把所有的其它字符都替换成*号,
但不包含数字。

如果只需要替换数字的话:
[root@kevin ~]# echo "hello world,root,2012" | tr "0-9" "*"  
hello world,root,****  

二,字符串的取值范围
指定string或string2的内容时,只能使用单字符或字符串范围或列表。
[a-z] a-z内的字符组成的字符串。
[A-Z] A-Z内的字符组成的字符串。
[0-9] 数字串。
\octal 一个三位的八进制数,对应有效的ASCII字符。
[O*n] 表示字符O重复出现指定次数n。因此[O*2]匹配OO的字符串。

三,控制字符的不同表达方式
速记符 含义 八进制方式
\a Ctrl-G  铃声\007
\b Ctrl-H 退格符\010
\f Ctrl-L  走行换页\014
\n Ctrl-J  新行\012
\r Ctrl-M 回车\015
\t  Ctrl-I  tab键\011
\v Ctrl-X \030 注意这些控制字符,如果想在linux下输入,如我们可能需要输入^M这种字符,只需ctrl+V+M同时按下即可。

四,字符替换
这是tr的默认操作,先看下面的命令和输出

[root@kevin ~]# echo "hello world" | tr "a-z" "A-Z"  
HELLO WORLD  
[root@kevin ~]# echo "hello world" | tr "a-l" "A-Z"  
HELLo worLD  
[root@kevin ~]# echo "hello world" | tr "a-z" "A-H"  
HEHHH HHHHD  
第一行输出就是将小写换成大写。
第二行输出将小写中的a-l分别换成A-L,而将小写中的l以后的字符都不替换。
第三行输出将小写中的a-h换成A-H,而h以后的字符都换成H,因为后者的替换空间没有前面的字符空间大,所以就重复后面的H,
相当于后面的字符是A-HHH......HHHHH。

如果我们想要进行大小写转换,可以按下面的输入:
tr "a-z" "A-Z" < inputfile  

五,去除重复字符
这个时候,所用的选项是-s选项,如:
[root@kevin ~]# echo "hello world,root" | tr -s "ao"  
hello world,rot  
[root@kevin ~]# echo "hello world,root" | tr -s "lo"  
helo world,rot  
[root@kevin ~]# echo "hello world,root" | tr -s "a-z"  
helo world,rot  
[root@kevin ~]# echo "hello world,root" | tr -s "0-9"  
hello world,root  
第一行表示将输入字符串中的包含在"ao"字符集中的重复字符去掉,只留一个。因为"hello world,root",只有o满足条件,所以将root变成rot,把中间的两个o变成一个。
第二行将hello和root两个字符都压缩了。
第三行表示将a-z中的除复字符都去掉。
第三行表示将字符串中的重复的且重复字符在0-9字符集中的字符去掉,这里没有。


如果我们想要去掉空行,可以这样操作:
tr -s "\n" < inputfile 或者 tr -s "\012" <inputfile // 这两个是一样的。  
就是将重复的换行符去掉,只留一个。

六,删除字符
-d选项和-s选项类似,只不过-d选项会删除所有出现的字符。
[root@kevin ~]# echo "hello world,root" | tr -d "a-h"  
llo worl,root  
[root@kevin ~]# echo "hello world,root,2012" | tr -d "a-z"  
 ,,2012  
[root@kevin ~]# echo "hello world,root,2012" | tr -d "0-9"

sort/uniq/cut/wc命令

sort 命令对 File 参数指定的文件中的行排序,并将结果写到标准输出。如果 File 参数指定多个文件,那么 sort 命令将这些文件连接起来,并当作一个文件进行排序。

sort语法
sort [-fbMnrtuk] [file or stdin]

选项与参数:
-f  :忽略大小写的差异,例如 A 与 a 视为编码相同;
-b  :忽略最前面的空格符部分;
-M  :以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
-n  :使用『纯数字』进行排序(默认是以文字型态来排序的);
-r  :反向排序;
-u  :就是 uniq ,相同的数据中,仅出现一行代表;
-t  :分隔符,默认是用 [tab] 键来分隔;
-k  :以那个区间 (field) 来进行排序的意思

对/etc/passwd 的账号进行排序
[root@kevin ~]# cat /etc/passwd | sort
adm:x:3:4:adm:/var/adm:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

sort 是默认以第一个数据来排序,而且默认是以字符串形式来排序,所以由字母 a 开始升序排序。

/etc/passwd 内容是以 : 来分隔的,我想以第三栏来排序,该如何
[root@kevin ~]# cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin

默认是以字符串来排序的,如果想要使用数字排序:
[root@kevin ~]# cat /etc/passwd | sort -t ':' -k 3n
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh

默认是升序排序,如果要倒序排序,如下
[root@kevin ~]# cat /etc/passwd | sort -t ':' -k 3nr
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
ntp:x:106:113::/home/ntp:/bin/false
messagebus:x:105:109::/var/run/dbus:/bin/false
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
 
如果要对/etc/passwd,先以第六个域的第2个字符到第4个字符进行正向排序,再基于第一个域进行反向排序。
[root@kevin ~]# cat /etc/passwd |  sort -t':' -k 6.2,6.4 -k 1r      
sync:x:4:65534:sync:/bin:/bin/sync
proxy:x:13:13:proxy:/bin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
 
查看/etc/passwd有多少个shell:对/etc/passwd的第七个域进行排序,然后去重:
[root@kevin ~]# cat /etc/passwd |  sort -t':' -k 7 -u
root:x:0:0:root:/root:/bin/bash
syslog:x:101:102::/home/syslog:/bin/false
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
 
==================================================================
uniq命令可以去除排序过的文件中的重复行,因此uniq经常和sort合用。也就是说,为了使uniq起作用,所有的重复行必须是相邻的。

uniq语法
uniq [-icu]

选项与参数:
-i   :忽略大小写字符的不同;
-c  :进行计数
-u  :只显示唯一的行
 
[root@kevin ~]# cat testfile
hello
world
friend
hello
world
hello
 
直接删除未经排序的文件,将会发现没有任何行被删除
[root@kevin ~]# uniq testfile  
hello
world
friend
hello
world
hello

排序文件,默认是去重
[root@kevin ~]# cat words | sort |uniq
friend
hello
world
 
排序之后删除了重复行,同时在行首位置输出该行重复的次数
[root@kevin ~]# sort testfile | uniq -c
1 friend
3 hello
2 world
 
仅显示存在重复的行,并在行首显示该行重复的次数
[root@kevin ~]# sort testfile | uniq -dc
3 hello
2 world
 
仅显示不重复的行
[root@kevin ~]# sort testfile | uniq -u
friend  
 
===============================================
sort|uniq    排序去重
sort|uniq -c|srot -rn  排序去重,并降序
sort|uniq -c  打印重复的行数
sort|uniq -d  打印交集部分
sort|uniq -u  打印交集以外的部分
==============================================

[root@kevin ~]# cat a.txt 
sdfsdf
123
123
1234
123
dasdfsd
sdfsdf
asfd34234

[root@kevin ~]# cat a.txt |sort|uniq
123
1234
asfd34234
dasdfsd
sdfsdf

[root@kevin ~]# cat a.txt |sort|uniq -c
      3 123
      1 1234
      1 asfd34234
      1 dasdfsd
      2 sdfsdf

[root@kevin ~]# cat a.txt |sort|uniq -d
123
sdfsdf

[root@kevin ~]# cat a.txt |sort|uniq -u
1234
asfd34234
dasdfsd

[root@kevin ~]# cat a.txt 
sdfsdf
123
123
1234
123
dasdfsd
sdfsdf
asfd34234

[root@kevin ~]# cat b.txt 
sdf
123
err
2345
123
gggg

[root@kevin ~]# cat a.txt b.txt |sort|uniq
123
1234
2345
asfd34234
dasdfsd
err
gggg
sdf
sdfsdf

[root@kevin ~]# cat a.txt b.txt |sort|uniq -c
      5 123
      1 1234
      1 2345
      1 asfd34234
      1 dasdfsd
      1 err
      1 gggg
      1 sdf
      2 sdfsdf

[root@kevin ~]# cat a.txt b.txt |sort|uniq -d
123
sdfsdf

[root@kevin ~]# cat a.txt b.txt |sort|uniq -u
1234
2345
asfd34234
dasdfsd
err
gggg
sdf

=======================================================
cut命令可以从一个文本文件或者文本流中提取文本列。

cut语法
cut -d'分隔字符' -f fields <==用于有特定分隔字符
cut -c 字符区间            <==用于排列整齐的信息

选项与参数:
-d  :后面接分隔字符。与 -f 一起使用;
-f  :依据 -d 的分隔字符将一段信息分割成为数段,用 -f 取出第几段的意思;
-c  :以字符 (characters) 的单位取出固定字符区间;
 
PATH 变量如下
[root@kevin ~]# echo $PATH
/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games
# 1 | 2       | 3   | 4       | 5            | 6            | 7
 
将 PATH 变量取出,我要找出第五个路径。
[root@kevin ~]# echo $PATH | cut -d ':' -f 5
/usr/local/bin
 
将 PATH 变量取出,我要找出第三和第五个路径。
[root@kevin ~]# echo $PATH | cut -d ':' -f 3,5
/sbin:/usr/local/bin
 
将 PATH 变量取出,我要找出第三到最后一个路径。
[root@kevin ~]# echo $PATH | cut -d ':' -f 3-
/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games
 
将PATH 变量取出,我要找出第一到第三个路径。
[root@kevin ~]# echo $PATH | cut -d ':' -f 1-3
/bin:/usr/bin:/sbin:
 
将PATH 变量取出,我要找出第一到第三,还有第五个路径。
[root@kevin ~]# echo $PATH | cut -d ':' -f 1-3,5
/bin:/usr/bin:/sbin:/usr/local/bin
 
实用例子:只显示/etc/passwd的用户和shell
[root@kevin ~]# cat /etc/passwd | cut -d ':' -f 1,7 
root:/bin/bash
daemon:/bin/sh
bin:/bin/sh
 
====================================================
wc
统计文件里面有多少单词,多少行,多少字符。

wc语法
[root@kevin ~]# wc [-lwm]
选项与参数:
-l  :仅列出行;
-w  :仅列出多少字(英文单字);
-m  :多少字符;
 
默认使用wc统计/etc/passwd
[root@kevin ~]# wc /etc/passwd
40   45 1719 /etc/passwd
40是行数,45是单词数,1719是字节数

wc的命令比较简单使用,每个参数使用如下:
[root@kevin ~]# wc -l /etc/passwd   #统计行数,在对记录数时,很常用
40 /etc/passwd       #表示系统有40个账户

[root@kevin ~]# wc -w /etc/passwd  #统计单词出现次数
45 /etc/passwd

[root@kevin ~]# wc -m /etc/passwd  #统计文件的字节数
1719

split命令:切分文件

split命令用于将一个文件分割成数个。
该指令将大文件分割成较小的文件,在默认情况下将按照每1000行切割成一个小文件。

语法
split [--help][--version][-<行数>][-b <字节>][-C <字节>][-l <行数>][要切割的文件][输出文件名]

参数说明:
-<行数> : 指定每多少行切成一个小文件.如split -3 a.txt  
-b<字节> : 指定每多少字节切成一个小文件
-l, --lines=NUMBER:对file进行切分,每个文件有NUMBER行。
--help : 在线帮助
--version : 显示版本信息
-C<字节> : 与参数"-b"相似,但是在切 割时将尽量维持每行的完整性
[输出文件名] : 设置切割后文件的前置文件名, split会自动在前置文件名后再加上编号

示例1:
使用指令split将文件a.txt每3行切割成一个文件,输入如下命令:
注意:是按照a.txt文件中的行数进行分割的,每3行切分到一个文件中,切割成多个以"x"开头的小文件。直至所有行数被分完。
[root@kevin ~]# cat a.txt   
sdfsdf
123123123
sdfasdf2r345345
kljljkl
sjkdfjsdofopf
sadfsd2343
123123
asdf4555
66666
888888

[root@kevin ~]# split -3 a.txt 
[root@kevin ~]# ls
anaconda-ks.cfg  a.txt  xaa  xab  xac  xad
[root@kevin ~]# cat xaa
sdfsdf
123123123
sdfasdf2r345345
[root@kevin ~]# cat xab
kljljkl
sjkdfjsdofopf
sadfsd2343
[root@kevin ~]# cat xac
123123
asdf4555
66666
[root@kevin ~]# cat xad
888888 

示例2:
有个文件要处理,因为很大,所以想把它切成若干份,每份N行,以便并行处理。
参数说明:
-b, --bytes=SIZE:对file进行切分,每个小文件大小为SIZE。可以指定单位b,k,m。
-l, --lines=NUMBER:对file进行切分,每个文件有NUMBER行。
prefix:分割后产生的文件名前缀。

示例:
假设要切分的文件为test.2012-08-16_17,大小1.2M,12081行。
1)
[root@kevin ~]# split -l 5000 test.2012-08-16_17  
生成xaa,xab,xac三个文件。
[root@kevin ~]# wc -l #看到三个文件行数如下:
5000 xaa
5000 xab
2081 xac
12081 总计

2)
[root@kevin ~]# split -b 600k test.2012-08-16_17  
生成xaa,xab两个文件
[root@kevin ~]# ls -lh #看到两个文件大小如下:
600K xaa
554K xab

3)
[root@kevin ~]# split -b 500k test.2012-08-16_17 example  
得到三个文件,文件名的前缀都是example
[root@kevin ~]# ls -lh  #看到文件信息如下:
500K exampleaa
500K exampleab
154K exampleac

示例3:
将一个大文件分成若干个小文件方法
例如将一个BLM.txt文件分成前缀为 BLM_ 的1000个小文件,后缀为系数形式,且后缀为4位数字形式
[root@kevin ~]# wc -l BLM.txt       #读出 BLM.txt 文件一共有多少行
[root@kevin ~]# split -l 2482 ../BLM/BLM.txt -d -a 4 BLM_

将文件 BLM.txt 分成若干个小文件,每个文件2482行(-l 2482),文件前缀为BLM_ ,系数不是字母而是数字(-d),后缀系数为四位数(-a 4)

=====================================================
Linux下文件分割可以通过split命令来实现,可以指定按行数分割和安大小分割两种模式。Linux下文件合并可以通过cat命令来实现,非常简单。
在Linux下用split进行文件分割:

模式一:指定分割后文件行数
对与txt文本文件,可以通过指定分割后文件的行数来进行文件分割。
命令:split -l 300 large_file.txt new_file_prefix

模式二:指定分割后文件大小
split -b 10m server.log waynelog

对二进制文件我们同样也可以按文件大小来分隔。


在Linux下用cat进行文件合并:
命令:cat small_files* > large_file

将a.txt的内容输入到b.txt的末尾
cat a.txt >> b.txt

comm命令:对于两个已排序文件,逐行比对

一、常用用法
comm FILE1 FILE2

二、含义与选项
2.1、含义
对于两个已排序的文件,逐行比对。 
打印结果有3列:第1列,只属于“FILE1”的行;第2列,只属于“FILE2”的行;第3列,既属于“FILE1”,又属于“FILE2”的行。

2.2、选项表示的意思
“FILE1,FILE2”:指代已排序文件“FILE1”和“FILE2”

三、其他
3.1、“LC_COLLATE”等环境变量
由于涉及到两个字符串的比较等,故而程序实现中使用“LC_COLLATE”等环境变量,最终结果受到“LC_COLLATE”等环境变量的控制。

3.2、排序策略
comm命令实现设定的排序策略是“按照字典序排序”。两个已排序文件使用的排序策略组合共有3种情况。

3.2.1、情况1
一个排序文件按照字典序排序,另外一个排序文件按照非字典序(其他排序策略)排序。显而易见,在这种情况下,comm命令的执行结果会比较奇怪。
[root@localhost ~]# cat a.txt 
001
02
3
10
[root@localhost ~]# cat b.txt 
001
02
5
06
007
10
即已按照“数值大小”排序,执行“逐行比对”过程,我们的预期结果是:“3”只属于“c.txt”,“5,06,007”只属于“d.txt”,“001,02,10”共属于两个文件。

现在执行comm a.txt b.txt命令,得到如图1所示结果,不能达到预期。
[root@localhost ~]# comm a.txt b.txt 
                001
                02
3
comm: file 1 is not in sorted order
10
        5
comm: file 2 is not in sorted order
        06
        007
        10

执行comm --nocheck-order a.txt b.txt命令,得到如图2所示结果,也不能达到预期。
[root@localhost ~]# comm --nocheck-order a.txt b.txt
                001
                02
3
10
        5
        06
        007
        10


两个文件都已按照字典序排序,这符合comm命令实现的设定,comm命令的执行结果能够达到预期。执行下述命令,得到如图3所示结果,结果符合预期。
[root@localhost ~]# sort a.txt > aa.txt
[root@localhost ~]# sort b.txt > bb.txt
[root@localhost ~]# comm aa.txt bb.txt
                001
        007
                02
        06
                10
3
        5
[root@localhost ~]# cat aa.txt 
001
02
10
3
[root@localhost ~]# cat bb.txt 
001
007
02
06
10
5

join命令:根据两行中具有相同值的两个字段,将该两行内容拼接成一行打印输出

一、常用用法
join [-t CHAR] [-i] [--header] [-1 FIELD] [-2 FIELD] [-e STR] FILE1 FILE2

二、含义与选项
2.1、含义
存在两个已排序文件,假如文件1中的某条记录的某个字段值(默认是第一个字段,从1开始计数)与文件2中的某条记录的某个字段值
(默认是第一个字段,从1开始计数)一致,那么在最终打印结果中,将这两条记录拼接成一条记录。

2.2、选项表示的意思
“-t CHAR”:以“CHAR”字符作为记录内字段间的分隔符,默认的分隔符是“空格符” 
“-i”:两个字段值比较时,忽略大小写 
“–header”:两个文件的第一行作为说明行,不参与比较 
“-1 FIELD”:FILE1中以第“FIELD”个字段作为比较字段 
“-2 FIELD”:FILE2中以第“FIELD”个字段作为比较字段 
“-e STR”:在最终的拼接记录中,如果某个字段的值为空,那么以“STR”替换 
“FILE1”:文件1 
“FILE2”:文件2

示例一
有文件“a.txt”和“b.txt”,内容分别如下:
[root@localhost ~]# cat a.txt 
a 1
b 2
[root@localhost ~]# cat b.txt 
a 3
b 4

执行以下命令,得到如下结果:
[root@localhost ~]# join a.txt b.txt
a 1 3
b 2 4

示例二
有文件“a.txt”和“b.txt”,内容分别如下:
[root@localhost ~]# cat a.txt 
a;1
b;2
[root@localhost ~]# cat b.txt 
a;3
b;4

执行以下命令,得到如下结果:
[root@localhost ~]# join -t ';' a.txt b.txt
a;1;3
b;2;4

示例三
有文件“a.txt”和“b.txt”,内容分别如下:
[root@localhost ~]# cat a.txt 
A 1
b 2
[root@localhost ~]# cat b.txt 
a 3
b 4

执行以下命令,得到如下结果:
[root@localhost ~]# join -i a.txt b.txt
A 1 3
b 2 4

示例四
有文件“a.txt”和“b.txt”,内容分别如下:
[root@localhost ~]# cat a.txt 
Col1 Col2
a 1
b 2
[root@localhost ~]# cat b.txt 
Col3 Col4
a 3
b 4

执行以下命令,得到如下结果:
[root@localhost ~]# join --header a.txt b.txt
Col1 Col2 Col4
a 1 3
b 2 4

示例五
有文件“a.txt”和“b.txt”,内容分别如下:
[root@localhost ~]# cat a.txt 
a 1 f
b 2 g
[root@localhost ~]# cat b.txt 
f 3 5
g 4 6

执行以下命令,得到如下结果:
[root@localhost ~]# join -1 3 -2 1 a.txt b.txt
f a 1 3 5
g b 2 4 6

示例六
有文件“a.txt”和“b.txt”,内容分别如下:
[root@localhost ~]# cat a.txt 
a 
b 2
[root@localhost ~]# cat b.txt 
a 3
b 4

执行以下命令,得到如下结果:
[root@localhost ~]# join -e "hello world" a.txt b.txt
a hello world 3
b 2 4

四、其他
4.1、“LC_COLLATE”等环境变量
由于涉及到两个字符串的比较等,故而程序实现中使用“LC_COLLATE”等环境变量,最终结果受到“LC_COLLATE”等环境变量的控制。

4.2、排序策略
跟“comm”命令一样,join命令实现设定的排序策略是“按照字典序排序”。因而,两个文件“已排序”应该是按照字典序已排序,否则执行join命令得到的结果很有可能不能符合预期。
上一篇:Centos下SVN环境部署记录


下一篇:Linux粘滞位使用 - 运维笔记 (t权限)