Linux学习笔记-5

1.Shell操作日期时间

date

在类UNIX系统中,日期被存储为一个整数,其大小为自世界标准时间(UTC)1970年1月1日0时0分0秒起流逝的秒数。

  1. 语法

    1
    date(选项)(参数)
  2. 选项

    1
    2
    3
    4
    5
    -d<字符串>:显示字符串所指的日期与时间。字符串前后必须加上双引号;
    -s<字符串>:根据字符串来设置日期与时间。字符串前后必须加上双引号;
    -u:显示GMT, 即目前的格林威治时间;
    --help:在线帮助;
    --version:显示版本信息。
  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
    %r 时间,12小时制
    %s 从1970年1月1日0点到目前经历的秒数
    %S 秒(00~59)
    %T 时间(24小时制)(hh:mm:ss)
    %X 显示时间的格式(%H时%M分%S秒)
    %Z 按字母表排序的时区缩写
    %a 星期名缩写
    %A 星期名全称
    %b 月名缩写
    %B 月名全称
    %c 日期和时间
    %d 按月计的日期(01~31)
    %D 日期(mm/dd/yy)
    %h 和%b选项相同
    %j 一年的第几天(001~366)
    %m 月份(01~12)
    %w 一个星期的第几天(0代表星期天)
    %W 一年的第几个星期(00~53,星期一为第一天)
    %x 显示日期的格式(mm/dd/yy)
    %y 年份的最后两个数字(1999则是99)
    %Y 年份(比如1970、1996等)
    %C 世纪,通常为省略当前年份的后两位数字
    %U 一年中的第几周,以周日为每星期第一天
    %e 按月计的日期,添加空格,等于%_d
  5. 实例

    格式化输出

    1
    2
    date +"%Y-%m-%d"
    2009-12-07

    输出昨天日期:

    1
    2
    date -d "1 day ago" +"%Y-%m-%d"
    2012-11-19

    2秒后输出:

    1
    2
    date -d "2 second" +"%Y-%m-%d %H:%M.%S"
    2012-11-20 14:21.31

    传说中的 1234567890 秒:

    1
    2
    date -d "1970-01-01 1234567890 seconds" +"%Y-%m-%d %H:%m:%S"
    2009-02-13 23:02:30

    普通转格式:

    1
    2
    date -d "2009-12-12" +"%Y/%m/%d %H:%M.%S"
    2009/12/12 00:00.00

    apache格式转换:

    1
    2
    date -d "Dec 5, 2009 12:00:37 AM" +"%Y-%m-%d %H:%M.%S"
    2009-12-05 00:00.37

    格式转换后时间游走:

    1
    2
    date -d "Dec 5, 2009 12:00:37 AM 2 year ago" +"%Y-%m-%d %H:%M.%S"
    2007-12-05 00:00.37

    加减操作:

    1
    2
    3
    4
    5
    6
    7
    date +%Y%m%d                   //显示前天年月日
    date -d "+1 day" +%Y%m%d //显示前一天的日期
    date -d "-1 day" +%Y%m%d //显示后一天的日期
    date -d "-1 month" +%Y%m%d //显示上一月的日期
    date -d "+1 month" +%Y%m%d //显示下一月的日期
    date -d "-1 year" +%Y%m%d //显示前一年的日期
    date -d "+1 year" +%Y%m%d //显示下一年的日期

    设定时间:

    1
    2
    3
    4
    5
    6
    7
    date -s                        //设置当前时间,只有root权限才能设置,其他只能查看
    date -s 20120523 //设置成20120523,这样会把具体时间设置成空00:00:00
    date -s 01:01:01 //设置具体时间,不会对日期做更改
    date -s "01:01:01 2012-05-23" //这样可以设置全部时间
    date -s "01:01:01 20120523" //这样可以设置全部时间
    date -s "2012-05-23 01:01:01" //这样可以设置全部时间
    date -s "20120523 01:01:01" //这样可以设置全部时间

    有时需要检查一组命令花费的时间,举例:

    1
    2
    3
    4
    5
    6
    7
    8
    #!/bin/bash

    start=$(date +%s)
    nmap man.linuxde.net &> /dev/null

    end=$(date +%s)
    difference=$(( end - start ))
    echo $difference seconds.

    计算活了多少年

    1
    echo $[($(date +%s -d $[date])-$(date +%s -d "19900318"))/86400/365]
  6. date -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
    ## 获取下一天的时间
    [root@hadoop ~]# date -d next-day '+%Y-%m-%d %H:%M:%S'
    [root@hadoop ~]# date -d 'next day' '+%Y-%m-%d %H:%M:%S'
    另外一种写法:
    [root@hadoop ~]# date '+%Y-%m-%d %H:%M:%S' -d tomorrow

    ## 获取上一天的时间
    [root@hadoop ~]# date -d last-day '+%Y-%m-%d %H:%M:%S'
    另外一种写法:
    [root@hadoop ~]# date '+%Y-%m-%d %H:%M:%S' -d yesterday

    ## 获取下一月的时间
    [root@hadoop ~]# date -d next-month '+%Y-%m-%d %H:%M:%S'

    ## 获取上一月的时间
    [root@hadoop ~]# date -d last-month '+%Y-%m-%d %H:%M:%S'

    ## 获取下一年的时间
    [root@hadoop ~]# date -d next-year '+%Y-%m-%d %H:%M:%S'

    ## 获取上一年的时间
    [root@hadoop ~]# date -d last-year '+%Y-%m-%d %H:%M:%S'

    ## 获取上一周的日期时间:
    [root@hadoop ~]# date -d next-week '+%Y-%m-%d %H:%M:%S'
    [root@hadoop ~]# date -d next-monday '+%Y-%m-%d %H:%M:%S'
    [root@hadoop ~]# date -d next-thursday '+%Y-%m-%d %H:%M:%S'

    那么类似的,其实,last-year,last-month,last-day,last-week,last-hour,last-minute,last-second都有对应的实现。相反的,last对应next,自己可以根据实际情况灵活组织

  7. 接下来,我们来看‘–date’,它帮我实现任意时间前后的计算,来看具体的例子:

    1
    2
    3
    4
    5
    6
    7
    ## 获取一天以后的日期时间
    [root@hadoop ~]# date '+%Y-%m-%d %H:%M:%S' --date='1 day'
    [root@hadoop ~]# date '+%Y-%m-%d %H:%M:%S' --date='-1 day ago'

    ## 获取一天以前的日期时间
    [root@hadoop ~]# date '+%Y-%m-%d %H:%M:%S' --date='-1 day'
    [root@hadoop ~]# date '+%Y-%m-%d %H:%M:%S' --date='1 day ago'

    上面的例子显示出来了使用的格式,使用精髓在于改变前面的字符串显示格式,改变数据,改变要操作的日期对应字段,除了天也有对应的其他实现:year,month,week,day,hour,minute,second,monday(星期,七天都可)

  8. date 能用来显示或设定系统的日期和时间,在显示方面,使用者能设定欲显示的格式,格式设定为一个加号后接数个标记,其中可用的标记列表如下:

    使用范例:

    1
    [root@hadoop ~]# date '+%Y-%m-%d %H:%M:%S'

    日期方面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    %a : 星期几 (Sun..Sat) 
    %A : 星期几 (Sunday..Saturday)
    %b : 月份 (Jan..Dec)
    %B : 月份 (January..December)
    %c : 直接显示日期和时间
    %d : 日 (01..31)
    %D : 直接显示日期 (mm/dd/yy)
    %h : 同 %b
    %j : 一年中的第几天 (001..366)
    %m : 月份 (01..12)
    %U : 一年中的第几周 (00..53) (以 Sunday 为一周的第一天的情形)
    %w : 一周中的第几天 (0..6)
    %W : 一年中的第几周 (00..53) (以 Monday 为一周的第一天的情形)
    %x : 直接显示日期 (mm/dd/yyyy)
    %y : 年份的最后两位数字 (00.99)
    %Y : 完整年份 (0000..9999)

    时间方面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    %%: 打印出%
    %n : 下一行
    %t : 跳格
    %H : 小时(00..23)
    %k : 小时(0..23)
    %l : 小时(1..12)
    %M : 分钟(00..59)
    %p : 显示本地AM或PM
    %P : 显示本地am或pm
    %r : 直接显示时间(12 小时制,格式为 hh:mm:ss [AP]M)
    %s : 从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数
    %S : 秒(00..61)
    %T : 直接显示时间(24小时制)
    %X : 相当于%H:%M:%S %p
    %Z : 显示时区
  9. 若是不以加号作为开头,则表示要设定时间,而时间格式为 MMDDhhmm[[CC]YY][.ss]

    1
    2
    3
    4
    5
    6
    7
    MM 为月份, 
    DD 为日,
    hh 为小时,
    mm 为分钟,
    CC 为年份前两位数字,
    YY 为年份后两位数字,
    ss 为秒数
  10. 有用的小技巧

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    ## 获取相对某个日期前后的日期:
    cts1 ~ # date -d 'may 14 -2 weeks'
    2018年 04月 30日 星期一 00:00:00 CST

    ## 把时间当中无用的0去掉,比如:01:02:25会变成1:2:25
    cts1 ~ # date '+%-H:%-M:%-S'
    19:18:22

    ## 显示文件最后被更改的时间
    cts1 ~ # date "+%Y-%m-%d %H:%M:%S" -r install.log
    2018-05-23 10:11:14

    ## 求两个字符串日期之间相隔的天数
    [root@hadoop ~]#
    expr '(' $(date +%s -d "2016-08-08") - $(date +%s -d "2016-09-09") ')' / 86400
    expr `expr $(date +%s -d "2016-08-08") - $(date +%s -d "2016-09-09")` / 86400

    ## shell中加减指定间隔单位
    cts1 ~ # A=`date +%Y-%m-%d`
    cts1 ~ # B=`date +%Y-%m-%d -d "$A +48 hours"`
    cts1 ~ # echo $B
    2018-05-30

2. 文本处理

wc

功能: 统计文件行数、字节、字符数

选项

1
2
3
4
5
6
7
-c # 统计字节数,或--bytes或——chars:只显示Bytes数;。
-l # 统计行数,或——lines:只显示列数;。
-m # 统计字符数。这个标志不能与 -c 标志一起使用。
-w # 统计字数,或——words:只显示字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
-L # 打印最长行的长度。
-help # 显示帮助信息
--version # 显示版本信息

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
wc -l *       # 统计当前目录下的所有文件行数
wc -l *.js # 统计当前目录下的所有 .js 后缀的文件行数
find . * | xargs wc -l # 当前目录以及子目录的所有文件行数
wc test.txt # 查看文件的字节数、字数、行数

# 查看文件的字节数、字数、行数
wc test.txt
# 输出结果
7 8 70 test.txt
行数 单词数 字节数 文件名

# 用wc命令只打印统计文件行数不打印文件名
wc -l test.txt
# 输出结果
7 test.txt

# 用来统计当前目录下的文件数
ls -l | wc -l
# 输出结果
8

# 统计文件字数:
cts1 ~ # wc -w date.txt
30 date.txt

sort

sort命令 是在Linux里非常有用,它将文件进行排序,并将排序结果标准输出。sort命令既可以从特定的文件,也可以从stdin中获取输入。

选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-b:忽略每行前面开始出的空格字符;
-c:检查文件是否已经按照顺序排序;
-d:排序时,处理英文字母、数字及空格字符外,忽略其他的字符;
-f:排序时,将小写字母视为大写字母;
-i:排序时,除了040至176之间的ASCII字符外,忽略其他的字符;
-m:将几个排序号的文件进行合并;
-M:将前面3个字母依照月份的缩写进行排序;
-n:依照数值的大小排序;
-o<输出文件>:将排序后的结果存入制定的文件;
-r:以相反的顺序来排序;
-t<分隔字符>:指定排序时所用的栏位分隔字符;
-g:按照常规数值排序
-k:位置1,位置2根据关键字排序,在从第位置1开始,位置2结束

+<起始栏位>-<结束栏位>:以指定的栏位来排序,范围由起始栏位到结束栏位的前一栏位。

实例

  1. sort将文件/文本的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    root@[mail text]# cat sort.txt
    aaa:10:1.1
    ccc:30:3.3
    ddd:40:4.4
    bbb:20:2.2
    eee:50:5.5
    eee:50:5.5

    [root@mail text]# sort sort.txt
    aaa:10:1.1
    bbb:20:2.2
    ccc:30:3.3
    ddd:40:4.4
    eee:50:5.5
    eee:50:5.5
  2. 忽略相同行使用-u选项或者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@mail text]# cat sort.txt
    aaa:10:1.1
    ccc:30:3.3
    ddd:40:4.4
    bbb:20:2.2
    eee:50:5.5
    eee:50:5.5

    [root@mail text]# sort -u sort.txt
    aaa:10:1.1
    bbb:20:2.2
    ccc:30:3.3
    ddd:40:4.4
    eee:50:5.5

    或者

    [root@mail text]# uniq sort.txt
    aaa:10:1.1
    ccc:30:3.3
    ddd:40:4.4
    bbb:20:2.2
    eee:50:5.5
  3. sort的-n、-r、-k、-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
    30
    31
    32
    33
    [root@mail text]# cat sort.txt
    AAA:BB:CC
    aaa:30:1.6
    ccc:50:3.3
    ddd:20:4.2
    bbb:10:2.5
    eee:40:5.4
    eee:60:5.1

    #将BB列按照数字从小到大顺序排列:
    [root@mail text]# sort -nk 2 -t: sort.txt
    AAA:BB:CC
    bbb:10:2.5
    ddd:20:4.2
    aaa:30:1.6
    eee:40:5.4
    ccc:50:3.3
    eee:60:5.1

    #将CC列数字从大到小顺序排列:
    [root@mail text]# sort -nrk 3 -t: sort.txt
    eee:40:5.4
    eee:60:5.1
    ddd:20:4.2
    ccc:50:3.3
    bbb:10:2.5
    aaa:30:1.6
    AAA:BB:CC

    # -n是按照数字大小排序,-r是以相反顺序,-k是指定需要排序的栏位,-t指定栏位分隔符为冒号

    # 多列排序:以:分隔,按第二列数值排倒序,第三列正序
    [linux@linux ~]$ sort -n -t: -k2,2r -k3 sort.txt
  4. -k选项的具体语法格式: x,x 表示一个范围

    1
    2
    3
    FStart.CStart Modifie,FEnd.CEnd Modifier
    -------Start--------,-------End--------
    FStart.CStart 选项 , FEnd.CEnd 选项

    这个语法格式可以被其中的逗号,分为两大部分, Start 部分和 End 部分。Start部分也由三部分组成,其中的Modifier部分就是我们之前说过的类似n和r的选项部分。我们重点说说Start部分的FStartC.StartC.Start也是可以省略的,省略的话就表示从本域的开头部分开始。FStart.CStart,其中FStart就是表示使用的域,而CStart则表示在FStart域中从第几个字符开始算“排序首字符”。同理,在End部分中,你可以设定FEnd.CEnd,如果你省略.CEnd,则表示结尾到“域尾”,即本域的最后一个字符。或者,如果你将CEnd设定为0(零),也是表示结尾到“域尾”。

  5. 从公司英文名称的第二个字母开始进行排序:

    1
    2
    3
    4
    5
    6
    7
    # 先创建此txt文件
    # 再排序
    $ sort -t ' ' -k 1.2 facebook.txt
    baidu 100 5000
    sohu 100 4500
    google 110 5000
    guge 50 3000

    -t ' ', 首先用' '空格, 把字段分割成了3个域.

    使用了-k 1.2,表示对第一个域的第二个字符开始到本域的最后一个字符为止的字符串进行排序。你会发现baidu因为第二个字母是a而名列榜首。sohu和 google第二个字符都是o,但sohu的h在google的o前面,所以两者分别排在第二和第三。guge只能屈居第四了。

  6. 只针对公司英文名称的第二个字母进行排序,如果相同的按照员工工资进行降序排序:

    1
    2
    3
    4
    5
    $ sort -t ' ' -k 1.2,1.2 -nrk 3,3 facebook.txt
    baidu 100 5000
    google 110 5000
    sohu 100 4500
    guge 50 3000

    由于只对第二个字母进行排序,所以我们使用了-k 1.2,1.2的表示方式,表示我们“只”对第二个字母进行排序。(如果你问“我使用-k 1.2怎么不行?”,当然不行,因为你省略了End部分,这就意味着你将对从第二个字母起到本域最后一个字符为止的字符串进行排序)。对于员工工资进行排 序,我们也使用了-k 3,3,这是最准确的表述,表示我们“只”对本域进行排序,因为如果你省略了后面的3,就变成了我们“对第3个域开始到最后一个域位置的内容进行排序” 了。

uniq

uniq命令 用于报告或忽略文件中的重复行,一般与sort命令结合使用。

选项

1
2
3
4
5
6
-c或——count:在每列旁边显示该行重复出现的次数;
-d或--repeated:仅显示重复出现的行列;
-f<栏位>或--skip-fields=<栏位>:忽略比较指定的栏位;
-s<字符位置>或--skip-chars=<字符位置>:忽略比较指定的字符;
-u或——unique:仅显示出一次的行列;
-w<字符位置>或--check-chars=<字符位置>:指定要比较的字符。

参数

  • 输入文件:指定要去除的重复行文件。如果不指定此项,则从标准读取数据;
  • 输出文件:指定要去除重复行后的内容要写入的输出文件。如果不指定此选项,则将内容显示到标准输出设备(显示终端)。

实例

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
[root]# cat sort.txt	: 原本行
aaa:10:1.1
ccc:30:3.3
ddd:40:4.4
bbb:20:2.2
eee:50:5.5
eee:50:5.5

[root]# uniq sort.txt : 不展示重复行
aaa:10:1.1
ccc:30:3.3
ddd:40:4.4
bbb:20:2.2
eee:50:5.5
[cts1:Desktop]

[cts1:Desktop]
[root]# sort sort.txt | uniq : 不展示重复行
aaa:10:1.1
bbb:20:2.2
ccc:30:3.3
ddd:40:4.4
eee:50:5.5

[cts1:Desktop]
[root]# uniq -u sort.txt : 删除重复行
aaa:10:1.1
ccc:30:3.3
ddd:40:4.4
bbb:20:2.2
[cts1:Desktop]
[root]# sort sort.txt | uniq -u : 排序并删除重复行
aaa:10:1.1
bbb:20:2.2
ccc:30:3.3
ddd:40:4.4
[cts1:Desktop]
[root]# sort sort.txt | uniq -c : 展示每行出现的次数
1 aaa:10:1.1
1 bbb:20:2.2
1 ccc:30:3.3
1 ddd:40:4.4
2 eee:50:5.5
[cts1:Desktop]
[root]# sort sort.txt | uniq -d : 只展示重复行
eee:50:5.5

# 求a.txt和b.txt的差集
## 首先a b 去掉重复的, 再跟a b去重, 把b其它的部分也去掉
cts1 Desktop # cat a b b | sort | uniq -u
a
b

# 求b.txt和a.txt的差集
## 同上
cts1 Desktop # cat b a a | sort | uniq -u
e
f

cut

cut命令 用来显示行中的指定部分,删除文件中指定字段。cut经常用来显示文件的内容,类似于下的type命令。

说明:该命令有两项功能,其一是用来显示文件的内容,它依次读取由参数file所指 明的文件,将它们的内容输出到标准输出上;其二是连接两个或多个文件,如cut fl f2 > f3将把文件fl和几的内容合并起来,然后通过输出重定向符“>”的作用,将它们放入文件f3中。

当文件较大时,文本在屏幕上迅速闪过(滚屏),用户往往看不清所显示的内容。因此,一般用more等命令分屏显示。为了控制滚屏,可以按Ctrl+S键,停止滚屏;按Ctrl+Q键可以恢复滚屏。按Ctrl+C(中断)键可以终止该命令的执行,并且返回Shell提示符状态。

选项

1
2
3
4
5
6
7
8
9
-b:仅显示行中指定直接范围的内容;
-c:仅显示行中指定范围的字符;
-d:指定字段的分隔符,默认的字段分隔符为“TAB”;
-f:显示指定字段的内容;
-n:与“-b”选项连用,不分割多字节字符;
--complement:补足被选择的字节、字符或字段;
--out-delimiter=<字段分隔符>:指定输出内容是的字段分割符;
--help:显示指令的帮助信息;
--version:显示指令的版本信息。

参数

文件:指定要进行内容过滤的文件。

实例

例如有一个学生报表信息,包含No、Name、Mark、Percent:

1
2
3
4
5
[root@localhost text]# cat cut.txt 
No Name Mark Percent
01 tom 69 91
02 jack 71 87
03 alex 68 98
-f

使用-f 选项提取指定字段

1
2
3
4
5
[root@localhost text]# cut -d ' ' -f1 cut.txt 
No
01
02
03
1
2
3
4
5
[root@localhost text]# cut -d ' ' -f2,3 test.txt 
Name Mark
tom 69
jack 71
alex 68
–complement

选项提取指定字段之外的列(打印除了第二列之外的列):

1
2
3
4
5
cut -d ' ' -f2 --complement cut.txt
No Mark Percent
01 69 91
02 71 87
03 68 98
指定字段的字符或者字节范围 & 例子

cut命令可以将一串字符作为列来显示,字符字段的记法:

  • N- :从第N个字节、字符、字段到结尾;
  • N-M :从第N个字节、字符、字段到第M个(包括M在内)字节、字符、字段;
  • -M :从第1个字节、字符、字段到第M个(包括M在内)字节、字符、字段。

上面是记法,结合下面选项将摸个范围的字节、字符指定为字段:

  • -b 表示字节;
  • -c 表示字符;
  • -f 表示定义字段。
实例
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
[root@localhost text]# cat test.txt 
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz

# 打印第1个到第3个字符:
cut -c1-3 test.txt
abc
abc
abc
abc
abc

# 打印前2个字符:
cut -c-2 test.txt
ab
ab
ab
ab
ab

# 打印从第5个字符开始到结尾:
cut -c5- test.txt
efghijklmnopqrstuvwxyz
efghijklmnopqrstuvwxyz
efghijklmnopqrstuvwxyz
efghijklmnopqrstuvwxyz
efghijklmnopqrstuvwxyz

grep(文本生成器)

grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。用于过滤/搜索的特定字符。可使用正则表达式能多种命令配合使用,使用上十分灵活。

选项

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
-a --text  # 不要忽略二进制数据。
-A <显示行数> --after-context=<显示行数> # 除了显示符合范本样式的那一行之外,并显示该行之后的内容。
-b --byte-offset # 在显示符合范本样式的那一行之外,并显示该行之前的内容。
-B<显示行数> --before-context=<显示行数> # 除了显示符合样式的那一行之外,并显示该行之前的内容。
-c --count # 计算符合范本样式的列数。
-C<显示行数> --context=<显示行数>或-<显示行数> # 除了显示符合范本样式的那一列之外,并显示该列之前后的内容。
-d<进行动作> --directories=<动作> # 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep命令将回报信息并停止动作。
-e<范本样式> --regexp=<范本样式> # 指定字符串作为查找文件内容的范本样式。
-E --extended-regexp # 将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式。
-f<范本文件> --file=<规则文件> # 指定范本文件,其内容有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每一列的范本样式。
-F --fixed-regexp # 将范本样式视为固定字符串的列表。
-G --basic-regexp # 将范本样式视为普通的表示法来使用。
-h --no-filename # 在显示符合范本样式的那一列之前,不标示该列所属的文件名称。
-H --with-filename # 在显示符合范本样式的那一列之前,标示该列的文件名称。
-i --ignore-case # 忽略字符大小写的差别。
-l --file-with-matches # 列出文件内容符合指定的范本样式的文件名称。
-L --files-without-match # 列出文件内容不符合指定的范本样式的文件名称。
-n --line-number # 在显示符合范本样式的那一列之前,标示出该列的编号。
-q --quiet或--silent # 不显示任何信息。
-R/-r --recursive # 此参数的效果和指定“-d recurse”参数相同。
-s --no-messages # 不显示错误信息。
-v --revert-match # 反转查找。
-V --version # 显示版本信息。
-w --word-regexp # 只显示全字符合的列。
-x --line-regexp # 只显示全列符合的列。
-y # 此参数效果跟“-i”相同。
-o # 只输出文件中匹配到的部分。

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
<sup>    # 锚定行的开始 如:'</sup>grep'匹配所有以grep开头的行。    
$ # 锚定行的结束 如:'grep$'匹配所有以grep结尾的行。
. # 匹配一个非换行符的字符 如:'gr.p'匹配gr后接一个任意字符,然后是p。
* # 匹配零个或多个先前字符 如:'*grep'匹配所有一个或多个空格后紧跟grep的行。
.* # 一起用代表任意字符。
[] # 匹配一个指定范围内的字符,如'[Gg]rep'匹配Grep和grep。
[<sup>] # 匹配一个不在指定范围内的字符,如:'[</sup>A-FH-Z]rep'匹配不包含A-R和T-Z的一个字母开头,紧跟rep的行。
\ # 转义
\(..\) # 标记匹配字符,如'\(love\)',love被标记为1。
\< # 锚定单词的开始,如:'\<grep'匹配包含以grep开头的单词的行。
\> # 锚定单词的结束,如'grep\>'匹配包含以grep结尾的单词的行。
x\{m\} # 重复字符x,m次,如:'o\{5\}'匹配包含5个o的行。
x\{m,\} # 重复字符x,至少m次,如:'o\{5,\}'匹配至少有5个o的行。
x\{m,n\} # 重复字符x,至少m次,不多于n次,如:'o\{5,10\}'匹配5--10个o的行。
\w # 匹配文字和数字字符,也就是[A-Za-z0-9],如:'G\w*p'匹配以G后跟零个或多个文字或数字字符,然后是p。
\W # \w的反置形式,匹配一个或多个非单词字符,如点号句号等。
\b # 单词锁定符,如: '\bgrep\b'只匹配grep。

增录
. # 任意一个字符
a* # 任意多个a(0个或多个)
a? # 0个或1个a
a+ # 一个或多个a
[A-Z]
[ABC]

grep命令常见用法

  1. 在文件中搜索一个单词,命令会返回一个包含 “match_pattern” 的文本行:

    1
    2
    grep match_pattern file_name
    grep "match_pattern" file_name
  2. 在多个文件中查找

    1
    grep "match_pattern" file_1 file_2 file_3 ...
  3. 输出除 “match_pattern” 之外的所有行 >> -v 选项:

    1
    grep -v "match_pattern" file_name
  4. 标记匹配颜色 –color=auto 选项:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    grep "match_pattern" file_name --color=auto

    eg: 查找当前目录下所有文件中的 `a`
    cts1 Desktop # grep "\(a\)" ./* --color=auto
    ---
    ./a:a
    ./abc.txt:abcdefghijklmnopqrstuvwxyz
    ./abc.txt:abcdefghijklmnopqrstuvwxyz
    ./abc.txt:abcdefghijklmnopqrstuvwxyz
    ...
  5. 使用正则表达式 -E 选项:

    1
    2
    3
    grep -E "[1-9]+"

    egrep "[1-9]+"
  6. 只输出文件中匹配到的部分 -o 选项:

    1
    2
    3
    4
    5
    echo this is a test line. | grep -o -E "[a-z]+\."
    line.

    echo this is a test line. | egrep -o "[a-z]+\."
    line.
  7. 统计文件或者文本中包含匹配字符串的行数 -c 选项:

    1
    grep -c "text" file_name
  8. 输出包含匹配字符串的行数 -n 选项:

    1
    2
    3
    4
    5
    6
    grep "text" -n file_name

    cat file_name | grep "text" -n

    #多个文件
    grep "text" -n file_1 file_2
  9. 打印样式匹配所位于的字符或字节偏移

    1
    2
    3
    4
    echo gun is not unix | grep -b -o "not"
    7:not

    #一行中字符串的字符便宜是从该行的第一个字符开始计算,起始值为0。选项 **-b -o** 一般总是配合使用。
  10. 搜索多个文件并查找匹配文本在哪些文件中

    1
    grep -l "text" file1 file2 file3...

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
# 在多级目录中对文本进行递归搜索
grep "text" . -r -n
# .表示当前目录。

# 忽略匹配样式中的字符大小写
echo "hello world" | grep -i "HELLO"
hello

# 选项 -e 制动多个匹配样式:
echo this is a text line | grep -e "is" -e "line" -o
is
line

#也可以使用 **-f** 选项来匹配多个样式,在样式文件中逐行写出需要匹配的字符。
cat patfile
aaa
bbb

# 用文件名称匹配, 实际上就是匹配文件中的内容
echo aaa bbb ccc ddd eee | grep -f patfile -o
aaa
bbb

# 在grep搜索结果中包括或者排除指定文件:
---
#只在目录中所有的.php和.html文件中递归搜索字符"main()"
grep "main()" . -r --include *.{php,html}

#在搜索结果中排除所有README文件
grep "main()" . -r --exclude "README"

#在搜索结果中排除filelist文件列表里的文件
grep "main()" . -r --exclude-from filelist
---

# 使用0值字节后缀的grep与xargs:
---
# 测试文件:
echo "aaa" > file1
echo "bbb" > file2
echo "aaa" > file3

grep "aaa" file* -lZ | xargs -0 rm

#执行后会删除file1和file3,grep输出用-Z选项来指定以0值字节作为终结符文件名(\0),xargs -0 读取输入并用0值字节终结符分隔文件名,然后删除匹配文件,-Z通常和-l结合使用。
# 好吧, 暂时我也没懂是啥意思...
---

# grep静默输出:
grep -q "test" filename
# 不会输出任何信息,如果命令运行成功返回0,失败则返回非0值。一般用于条件测试。

# 打印出匹配文本之前或者之后的行:
# 显示匹配某个结果之后的3行,使用 -A 选项:
seq 10 | grep "5" -A 3
5
6
7
8

# 显示匹配某个结果之前的3行,使用 -B 选项:
seq 10 | grep "5" -B 3
2
3
4
5

# 显示匹配某个结果的前三行和后三行,使用 -C 选项:
seq 10 | grep "5" -C 3
2
3
4
5
6
7
8

# 如果匹配结果有多个,会用“--”作为各匹配结果之间的分隔符:
echo -e "a\nb\nc\na\nb\nc" | grep a -A 1
a
b
--
a
b

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
# 统计出现某个字符串的行的总行数 '-c'
cts1 Desktop # echo "hello" >> hello.sh
cts1 Desktop # grep -c 'hello' hello.sh
1

# 查询不包含hello的行, 带有hello的整行都不会被查询到 '-v'
cts1 Desktop # grep -v 'hello' hello.sh
....

# `.*`的用法, 前后都是 `.*` , 只要包含 parrten 的 整行 都会被查出来
grep '.*hello.*' hello.sh

# 任何由 'h..p'包含的都会被查出来. 查的当前行, .* 代表任意字符
cts1 Desktop # grep 'h.*p' /etc/passwd
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nolo

# 正则表达以 ro 开头
cts1 Desktop # grep '^ro' /etc/passwd
root:x:0:0:root:/root:/bin/zsh

# 正则表达以 t 结尾
cts1 Desktop # grep 't$' /etc/passwd
halt:x:7:0:halt:/sbin:/sbin/halt

# '[Gg]rep'匹配Grep和grep
## 此处是匹配 以 h || r 开头的
cts1 Desktop #
grep '^[hr]' /etc/passwd
root:x:0:0:root:/root:/bin/zsh
halt:x:7:0:halt:/sbin:/sbin/halt
rpc:x:32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nologin

# 匹配非h之外其他的, 和 r 开头的, 也就是匹配 h以外的
cts1 Desktop #
grep '^[hr]' /etc/passwd
root:x:0:0:root:/root:/bin/zsh
halt:x:7:0:halt:/sbin:/sbin/halt
rpc:x:32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nologin

# 匹配 h-r 以外的
cts1 Desktop #
grep '<sup>[</sup>h-r]' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
...

sed(流编辑器)

sed叫做流编辑器,在shell脚本和Makefile中作为过滤一使用非常普遍,也就是把前一个程序的输出引入sed的输入,经过一系列编辑命令转换成为另一种格式输出。sed是一种在线编辑器,它一次处理一行内容,处理时,把当前处理的行存储在临时缓冲区中,称为”模式空间”,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。

选项

1
2
3
4
5
6
7
8
9
10
11
12
13
-n:一般sed命令会把所有数据都输出到屏幕,如果加入-n选项的话,则只会把经过sed命令处理的行输出到屏幕。
-e<script>或--expression=<script>:以选项中的指定的script来处理输入的文本文件; 允许对输入数据应用多条sed命令编辑。
-i:用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出。
-f<script文件>或--file=<script文件>:以选项中指定的script文件来处理输入的文本文件;
-n或--quiet或——silent:仅显示script处理后的结果;
--version:显示版本信息。

# 动作:
a:追加,在当前行后添加一行或多行。
c:行替换,用c后面的字符串替换原数据行。
i:插入,在当前行前插入一行或多行。
p:打印,输出指定的行。
s:字符串替换,用一个字符串替换另外一个字符串。格式为**\'**行范围s/旧字符串/新字符串/g**\'** (如果不加g的话,则表示只替换每行第一个匹配的串)

sed元字符集(正则)

1
2
3
4
5
6
7
8
9
10
11
12
13
**<sup>**  匹配行开始,如:/</sup>sed/匹配所有以sed开头的行。
**$** 匹配行结束,如:/sed$/匹配所有以sed结尾的行。
**.** 匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d。
**** * 匹配0个或多个字符,如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行。
**[]** 匹配一个指定范围内的字符,如/[ss]ed/匹配sed和Sed。
**[<sup>]** 匹配一个不在指定范围内的字符,如:/[</sup>A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行。
**\(..\)** 匹配子串,保存匹配的字符,如s/\(love\)able/\1rs,loveable被替换成lovers。
**&** 保存搜索字符用来替换其他字符,如s/love/ **&** /,love这成 **love** 。
**\<** 匹配单词的开始,如:/\<love/匹配包含以love开头的单词的行。
**\>** 匹配单词的结束,如/love\>/匹配包含以love结尾的单词的行。
**x\{m\}** 重复字符x,m次,如:/0\{5\}/匹配包含5个0的行。
**x\{m,\}** 重复字符x,至少m次,如:/0\{5,\}/匹配至少有5个0的行。
**x\{m,n\}** 重复字符x,至少m次,不多于n次,如:/0\{5,10\}/匹配5~10个0的行。

实例

  1. 删除: d命令

    sed ‘2d’ sed.txt —–删除sed.txt文件的第二行。

    sed ‘2,$d’ sed.txt —–删除sed.txt文件的第二行到末尾所有行。

    sed ‘$d’ sed.txt —–删除sed.txt文件的最后一行。

    sed ‘/test/d ‘ sed.txt —–删除sed.txt文件所有包含test的行。

    sed ‘/[A-Za-z]/d ‘ sed.txt —–删除sed.txt文件所有包含字母的行。

  2. 整行替换: c命令

    将第二行替换成hello world

    sed \’2c hello world\’ sed.txt

  3. 字符串替换:s命令

    1. sed ‘s/hello/hi/g’ sed.txt

      ## 在整行范围内把hello替换为hi。如果没有g标记,则只有每行第一个匹配的hello被替换成hi。

    1. sed ‘s/hello/hi/2’ sed.txt

      ## 此种写法表示只替换每行的第2个hello为hi

    1. sed ‘s/hello/hi/2g’ sed.txt

      ## 此种写法表示只替换每行的第2个以后的hello为hi(包括第2个)

    1. sed -n ‘s/^hello/hi/p’ sed.txt

      ## (-n)选项和p标志一起使用表示只打印那些发生替换的行。也就是说,如果某一行开头的hello被替换成hi,就打印它。

    1. sed -n ‘2,4p’ sed.txt

      ## 打印输出sed.txt中的第2行和第4行

    1. sed -n ‘s/hello/&-hi/gp’ sed.txt

      sed ‘s/^192.168.0.1/&-localhost/‘ sed.txt

      sed ‘s/^192.168.0.1/[&]/‘ sed.txt

      ## &符号表示追加一个串到找到的串后, &代表前一个串。

      所有以192.168.0.1开头的行都会被替换成它自已加 -localhost,变成192.168.0.1-localhost。

      第三句表示给IP地址添加中括号

    1. sed -n ‘s/(liu)jialing/\1tao/p’ sed.txt

      sed -n ‘s/(liu)jia(ling)/\1tao\2ss/p’ sed.txt

      ## liu被标记为\1,所以liu会被保留下来(\1 == liu)

      ## ling被标记为\2,所以ling也会被保留下来(\2 == ling)

      ## 所以最后的结果就是\1tao\2ss == “liu” + “tao” + “ling” + “ss”

      此处切记:\1代表的是被第一个()包含的内容,\1代表的是被第一个()包含的内容,……

      上面命令的意思就是:被括号包含的字符串会保留下来,然后跟其他的字符串比如tao和ss组成新的字符串liutaolingss

    1. sed ‘s#hello#hi#g’ sed.txt

      ## 不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,”#”在这里是分隔符,代替了默认的”/“分隔符。表示把所有hello替换成hi。

    选定行的范围:逗号

    1. sed -n ‘/today/,/hello/p’ sed.txt

      ## 所有在模板today和hello所确定的范围内的行都被打印。都找第一个,也就是说,从第一个today到第一个hello

    1. sed -n ‘5,/^hello/p’ sed.txt

      sed -n ‘/^hello/,8p’ sed.txt

      ## 打印从第五行开始到第一个包含以hello开始的行之间的所有行。

    2. sed ‘/today/,/hello/s/$/www/‘ sed.txt

      ## 对于模板today和hello之间的行,每行的末尾用字符串www替换。

      sed ‘/today/,/hello/s/^/www/‘ sed.txt

      ## 对于模板today和hello之间的行,每行的开头用字符串www替换。

    3. sed ‘/^[A-Za-z]/s/5/five/g’ sed.txt

      ## 将以字母开头的行中的数字5替换成five

  1. 多点编辑:e命令

    1. sed -e ‘1,5d’ -e ‘s/hello/hi/‘ sed.txt

      ## (-e)选项允许在同一行里执行多条命令。如例子所示,第一条命令删除1至5行,第二条命令用hello替换hi。命令的执行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。

    2. sed –expression=’s/hello/hi/‘ –expression=’/today/d’ sed.txt

      ## 一个比-e更好的命令是–expression。它能给sed表达式赋值。

  2. 从文件读入:r命令

    sed ‘/hello/r file’ sed.txt

    ## file里的内容被读进来,显示在与hello匹配的行下面,如果匹配多行,则file的内容将显示在所有匹配行的下面。

  3. 写入文件:w命令

    sed -n ‘/hello/w file’ sed.txt

    ## 在huangbo.txt中所有包含hello的行都被写入file里。

  4. 追加命令:a命令

    sed ‘/^hello/a\—>this is a example’ sed.txt

    ## ‘—>this is a example’被追加到以hello开头的行(另起一行)后面,sed要求命令a后面有一个反斜杠。

  5. 插入:i命令

    sed ‘/will/i\some thing new ————————-‘ sed.txt

    ## 如果test被匹配,则把反斜杠后面的文本插入到匹配行的前面。

  6. 下一个:n命令

    sed ‘/hello/{n; s/aa/bb/;}’ sed.txt 替换下一行的第一个aa

    sed ‘/hello/{n; s/aa/bb/g;}’ sed.txt 替换下一行的全部aa

    ## 如果hello被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,然后继续。

  7. 退出:q命令

    sed ‘10q’ sed.txt

    ## 打印完第10行后,退出sed。

    同样的写法: sed -n ‘1,10p ‘ sed.txt

awk(报表生成器)

Awk是一个强大的处理文本的编程语言工具,其名称得自于它的创始人Alfred Aho、Peter Weinberger和Brian Kernighan 姓氏的首个字母,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。简单来说awk就是扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行。

语法

1
2
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)

… TODO 待补充

实例

  1. 假设last -n 5的输出如下:

    1
    2
    3
    4
    5
    6
    root@cts1:~ # last -n 5
    root pts/1 192.168.170.1 Mon May 28 09:28 still logged in
    root pts/1 192.168.170.1 Sun May 27 20:53 - 07:21 (10:28)
    root pts/0 192.168.170.1 Sun May 27 19:39 still logged in
    reboot system boot 2.6.32-573.el6.x Sun May 27 19:34 - 14:48 (19:13)
    root pts/1 192.168.170.1 Sat May 26 20:43 - 22:36 (01:53)
  2. 只显示五个最近登录的账号:

    1
    2
    3
    4
    5
    6
    7
    8
    root@cts1:~ # last -n 5 | awk '{print $1}'
    root
    root
    root
    reboot
    root

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

    1
    2
    3
    4
    5
    6
    7
    8
    root@cts1:~ # cat /etc/passwd | awk -F':' '{print $1}'
    root
    bin
    daemon
    ...

    # 这种是awk+action的示例,每行都会执行action{print $1}。
    # -F指定域分隔符为':'
  4. 显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以tab键分割

    1
    2
    3
    4
    5
    root@cts1:~ # cat /etc/passwd | awk -F':' '{print $1"\t"$7}'
    root /bin/zsh
    bin /sbin/nologin
    daemon /sbin/nologin
    ...
  5. BEGIN and END

    如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加”blue,/bin/nosh”。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    root@cts1:~ # cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
    ---
    name,shell
    root,/bin/zsh
    bin,/sbin/nologin
    ...
    mysql,/bin/bash
    blue,/bin/nosh
    -------------------------

    root@cts1:~ # cat /etc/passwd | awk -F ':' 'BEGIN {print "name \t shell"} {print$1"\t"$7} END {print "blue,/bin/bash"}'
    ---
    name shell
    root /bin/zsh
    bin /sbin/nologin
    ...
    mysql /bin/bash
    blue,/bin/bash

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

  6. 搜索/etc/passwd有root关键字的所有行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    1. root@cts1:~ # awk  -F:  '/root/'  /etc/passwd
    ---
    root:x:0:0:root:/root:/bin/zsh
    operator:x:11:0:operator:/root:/sbin/nologin

    # 这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。

    2. 搜索支持正则,例如找root开头的: awk -F: '/^root/' /etc/passwd
    # 搜索/etc/passwd有root关键字的所有行,并显示对应的shell
    root@cts1:~
    # awk -F ':' '/root/{print $7}' /etc/passwd
    /bin/zsh
    /sbin/nologin

    # 这里指定了action{print $7}
  7. awk常见内置变量

    FILENAME:awk浏览的文件名

    FNR:浏览文件的记录数,也就是行数。awk是以行为单位处理的,所以每行就是一个记录

    NR:awk读取文件每行内容时的行号

    NF:浏览记录的域的个数。可以用它来输出最后一个域

    FS:设置输入域分隔符,等价于命令行-F选项

    OFS:输出域分隔符

    统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容

    1
    2
    3
    4
    root@cts1:~ # 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/zsh
    filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin

    使用printf替代print,可以让代码更加简洁,易读

    1
    2
    3
    4
    root@cts1:~ #  awk  -F ':'  '{printf("filename:%s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
    ---
    filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/zsh
    filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin

    指定输入分隔符,指定输出分隔符:

    1
    2
    3
    4
    5
    root@cts1:~ # awk 'BEGIN {FS=":"; OFS="\t"} {print $1, $2}' /etc/passwd
    ---
    root x
    bin x
    ...
  8. 实用例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # A:打印最后一列:
    awk -F: '{print $NF}' /etc/passwd
    awk -F: '{printf("%s\n",$NF);}' /etc/passwd

    # B:统计文件行数:
    awk 'BEGIN {x=0} {x++} END {print x}' /etc/passwd

    # C:打印9*9乘法表:
    awk 'BEGIN{for(n=0;n++<9;){for(i=0;i++<n;)printf i"*"n"="i*n" ";print ""}}'
    awk 'BEGIN {for(i=1;i<=9;i++){for(j=1;j<=i;j++){printf i"*"j"="i*j" ";}print ""}}'
    awk 'BEGIN {for(i=9;i>=1;i--){for(j=i;j>=1;j--){printf i"*"j"="i*j" ";}print ""}}'

    # D: 计算1-100 之和
    echo "sum" | awk 'BEGIN {sum=0;} {i=0;while(i<101){sum+=i;i++}} END {print sum}'
  9. 更多详细用法参见官网

find

功能: 搜索文件目录层次结构

格式: find path -option actions

find <路径> <选项> [表达式]

常用可选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-name 根据文件名查找,支持(\'\* \' , \'? \')

-type 根据文件类型查找(f-普通文件,c-字符设备文件,b-块设备文件,l-链接文件,d-目录)

-perm 根据文件的权限查找,比如 755

-user 根据文件拥有者查找

-group 根据文件所属组寻找文件

-size 根据文件小大寻找文件

-o 表达式 或

-a 表达式 与

-not 表达式 非

类型参数列表:

1
2
3
4
5
6
7
- **f**  普通文件
- **l** 符号连接
- **d** 目录
- **c** 字符设备
- **b** 块设备
- **s** 套接字
- **p** Fifo

示例

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
[linux@linux txt]$ ll   ## 准备的测试文件
total 248
-rw-rw-r--. 1 linux linux 235373 Apr 18 00:10 hw.txt
-rw-rw-r--. 1 linux linux 0 Apr 22 05:43 LINUX.pdf
-rw-rw-r--. 1 linux linux 3 Apr 22 05:50 liujialing.jpg
-rw-rw-r--. 1 linux linux 0 Apr 22 05:43 mingxing.pdf
-rw-rw-r--. 1 linux linux 57 Apr 22 04:40 mingxing.txt
-rw-rw-r--. 1 linux linux 66 Apr 22 05:15 sort.txt
-rw-rw-r--. 1 linux linux 214 Apr 18 10:08 test.txt
-rw-rw-r--. 1 linux linux 24 Apr 22 05:27 uniq.txt

[linux@linux txt]$ find /home/linux/txt/ -name "*.txt" ## 查找文件名txt结尾的文件
/home/linux/txt/uniq.txt
/home/linux/txt/mingxing.txt
/home/linux/txt/test.txt
/home/linux/txt/hw.txt
/home/linux/txt/sort.txt

## 忽略大小写查找文件名包含linux
[linux@linux txt]$ find /home/linux/txt -iname "*linux*"
/home/linux/txt/LINUX.pdf

## 查找文件名结尾是.txt或者.jpg的文件
[linux@linux txt]$ find /home/linux/txt/ \( -name "*.txt" -o -name "*.jpg" \)
/home/linux/txt/liujialing.jpg
/home/linux/txt/uniq.txt
/home/linux/txt/mingxing.txt
/home/linux/txt/test.txt
/home/linux/txt/hw.txt
/home/linux/txt/sort.txt
另一种写法:find /home/linux/txt/ -name "*.txt" -o -name "*.jpg"

# 使用正则表达式的方式去查找上面条件的文件:
[linux@linux txt]$ find /home/linux/txt/ -regex ".*\(\.txt\|\.jpg\)$"
/home/linux/txt/liujialing.jpg
/home/linux/txt/uniq.txt
/home/linux/txt/mingxing.txt
/home/linux/txt/test.txt
/home/linux/txt/hw.txt
/home/linux/txt/sort.txt

## 查找.jpg结尾的文件,然后删掉
[linux@linux txt]$ find /home/linux/txt -type f -name "*.jpg" -delete
[linux@linux txt]$ ll
total 248
-rw-rw-r--. 1 linux linux 235373 Apr 18 00:10 hw.txt
-rw-rw-r--. 1 linux linux 0 Apr 22 05:43 LINUX.pdf
-rw-rw-r--. 1 linux linux 0 Apr 22 05:43 mingxing.pdf
-rw-rw-r--. 1 linux linux 57 Apr 22 04:40 mingxing.txt
-rw-rw-r--. 1 linux linux 66 Apr 22 05:15 sort.txt
-rw-rw-r--. 1 linux linux 214 Apr 18 10:08 test.txt
-rw-rw-r--. 1 linux linux 24 Apr 22 05:27 uniq.txt


## 查找5天以内创建的 .sh 文件, 并显示创建/更改时间
find / -name "*sh" -mtime -5 |xargs ls -l

3. Shell操作字符串

字符串截取

Linux中操作字符串,也是一项必备的技能。其中尤以截取字符串更加频繁,下面为大家介绍几种常用方式,截取字符串

预先定义一个变量:WEBSITE=’http://hadoop//centos/huangbo.html'

  1. #截取,*任意的, 删除//左边字符串(包括制定的分隔符),保留右边字符串

    root@cts1:~ # echo ${WEBSITE#*//}
    hadoop//centos/huangbo.html

  2. ##截取删除左边字符串(包括指定的分隔符),保留右边字符串,和上边一个#不同的是,它一直找到最后,而不是像一个#那样找到一个就满足条件退出了。

    root@cts1:~ # echo ${WEBSITE##*//}
    centos/huangbo.html

  3. %截取,删除右边字符串(包括制定的分隔符),保留左边字符串

    root@cts1:~ # echo ${WEBSITE%//*}
    http://hadoop

  4. %%截取,删除右边字符串(包括指定的分隔符),保留左边字符串,和上边一个%不同的是,它一直找到最前,而不是像一个%那样找到一个就满足条件退出了。

    root@cts1:~ # echo ${WEBSITE%%//*}
    http:

  5. 从左边第几个字符开始,以及截取的字符的个数

    root@cts1:~ # echo ${WEBSITE:2:2}
    tp

  6. 从左边第几个字符开始,一直到结束

    root@cts1:~ # echo ${WEBSITE:2}
    tp://hadoop//centos/huangbo.html

  7. 从右边第几个字符开始,以及字符的个数, 从-4开始, 还是往右边截取

    root@cts1:~ # echo ${WEBSITE:0-4:2

    ht

  8. 从右边第几个字符开始,一直到结束

    root@cts1:~ # echo ${WEBSITE:0-4}
    html

  9. 利用awk进行字符串截取

    echo $WEBSITE | awk ‘{print substr($1,2,6)}’

    ttp://

  10. 利用cut进行字符串截取

    root@cts1:~ # echo $WEBSITE | cut -b 1-4 http

  11. 获取最后几个字符

    root@cts1:~ # echo ${WEBSITE:(-3)} tml

  12. 截取从倒数第3个字符后的2个字符

    root@cts1:~ # echo ${WEBSITE:(-3):2}
    tm

字符串替换

使用格式

${parameter/pattern/string}

例子

1
2
3
4
5
6
7
8
9
10
# 定义变量VAR:
[linux@linux ~]$ VAR="hello tom, hello kitty, hello xiaoming"

# 替换第一个hello, 用`/`:
[linux@linux ~]$ echo ${VAR/hello/hi}
hi tom, hello kitty, hello xiaoming

# 替换所有hello, 用'//':
[linux@linux ~]$ echo ${VAR//hello/hi}
hi tom, hi kitty, hi xiaoming

获取字符串长度

在此为大家提供五种方式获取某字符串的长度

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
# 在此为大家提供五种方式获取某字符串的长度

# 1. 使用wc -L命令
+----------------------------------------------------+
| echo ${WEBSITE} |wc -L |
| |
| 35 |
+----------------------------------------------------+

# 2. 使用expr的方式去计算
+---------------------------------------------------+
| expr length ${WEBSITE} |
| |
| 35 |
+---------------------------------------------------+

# 3. 通过awk + length的方式获取字符串长度
+---------------------------------------------------------------------------+
|echo ${WEBSITE} | awk '{print length($0)}' |
| |
| 35 |
+---------------------------------------------------------------------------+

# 4. 通过awk的方式计算以**\"\"**分隔的字段个数
+-------------------------------------------------------------------------+
| echo ${WEBSITE} |awk -F "" '{print NF}' |
| |
| 35 |
+-------------------------------------------------------------------------+

# 5. 通过\#的方式获取字符串(最简单,最常用)
+----------------------------------------------+
| echo ${#WEBSITE} |
| |
| 35 |
+----------------------------------------------+

4. 脚本自动安装MySql

这里先做个记录, 之后会整理一份更详细的文档出来.

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
#!/bin/bash

## auto install mysql
## 假如是第二次装,那么要先停掉服务,并且卸载之前的mysql
service mysql stop
EXISTS_RPMS=`rpm -qa | grep -i mysql`
echo ${EXISTS_RPMS}
for RPM in ${EXISTS_RPMS}
do
rpm -e --nodeps ${RPM}
done

## 删除残留文件
rm -fr /usr/lib/mysql
rm -fr /usr/include/mysql
rm -f /etc/my.cnf
rm -fr /var/lib/mysql

## 从服务器获取安装mysql的rpm包
wget http://linux/soft/MySQL-client-5.6.26-1.linux_glibc2.5.x86_64.rpm
wget http://linux/soft/MySQL-server-5.6.26-1.linux_glibc2.5.x86_64.rpm

## 删除之前的密码文件,以免产生干扰
rm -rf /root/.mysql_secret

## 安装服务器
rpm -ivh MySQL-server-5.6.26-1.linux_glibc2.5.x86_64.rpm

## 获取到生成的随机密码
##PSWD=`cat /root/.mysql_secret | awk -F ':' '{print substr($4,2,16)}'`
PSWD=` grep -v '^$' /root/.mysql_secret | awk -F ':' '{print substr($4,2,16)}'`
##PSWD=${PWD:1:16}

## 安装客户端
rpm -ivh MySQL-client-5.6.26-1.linux_glibc2.5.x86_64.rpm

## 然后删除刚刚下下来的rpm包
rm -rf MySQL-client-5.6.26-1.linux_glibc2.5.x86_64.rpm
rm -rf MySQL-server-5.6.26-1.linux_glibc2.5.x86_64.rpm

## 提示安装的步骤都完成了。
echo "install mysql server and client is done .!!!!!!"

## 打印出来刚刚生成的mysql初始密码
echo "random password is:${PSWD}"

## 开启mysql服务
service mysql start

# 手动第一次登陆,然后改掉密码
[root@hadoop bin]# mysql -uroot -pZjVIWvOGD18bT7oX
mysql> set PASSWORD=PASSWORD('root');


# 现在就可以写脚本链接mysql进行操作了
[root@hadoop bin]# vi initMysql.sh

#!/bin/bash

mysql -uroot -proot << EOF
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;
use mysql;
select host, user, password from user;
EOF
如果帮到你, 可以给我赞助杯咖啡☕️
0%