1. cut列提取命令
$ cut [options] filename
options:
-f 列号:提取第几列
-d 分隔符:按照指定分隔符分割列,默认是制表符进行分割。
例如,我们在系统中的/etc/passwd记录了所有的系统的用户信息,我们需要提取出所有的能够登录的用户的用户名,这里需要说明的是判断是否能够登录,只需要判断每行用户信息最后是否是/bin/bash即可。所以我们对应的命令如下:
[hadoop@hadoop001 data]$ grep "/bin/bash" /etc/passwd | cut -f 1 -d ":"
root
roger
hadoop
mysql
hdfs
llama
httpfs
mapred
yarn
可以看到这里已经截取出了所有能够登录的用户名,语句的意思就是先通过grep对文件进行行提取出包含有/bin/bash的行,提取出来后的信息,通过管道利用cut进行筛选,启动-d ":“的意思就是这里的分隔符是用”:"进行分割。
这里需要强调的一点是,对于cut命令而言只能进行简单的每一行格式固定的行进行分割,例如如果用空格进行分割,那么如果某一行两个字符串之间有多个空格,则通过cut进行切分的时候,它也会严格按照一个空格来进行切分,遇到第一个空格视为分隔符取出一列,紧接着由于还是空格所以会认为后续一列为空,所以cut对每一行的格式要求较为严格一致。
2. printf
这个printf是Linux最标准的输出命令,它识别输出内容十分笨,对于输出内容的所有格式都要指明的很清楚,通常使用它是因为在awk命令中只识别printf,而不是别echo命令,它的语法如下:
$ printf '输出样式' 输出内容
具体例如:
$ printf '%s\t%s\t%s\t%s\n' 12 33 44 55
12 33 44 55
[hadoop@hadoop001 data]$ printf '%s%s%s%s\n' 12 33 44 55
12334455
%s是字符串的意思 %i是整数 %m.nf意思是输出内容为m位总长度,其中小数点后n位的浮点数。
显然,可以看出对于需要输出的内容,连后面的空格都得必须在输出样式中说明清楚!
3. awk
语法如下:
$ awk '条件1{动作1}条件2{动作2}...' 文件名
例子:
[hadoop@hadoop001 data]$ awk '{printf $2 "\t" $4 "\n"}' student.txt
Name Mark
furong 88
fengjie 66
cangJK 90
这里对于awk流程需要进行一下说明,由于它和cut一样是进行列截取用的,在以上例子中,$n代表的是第几列,例子中取得是输出第二列和第四列,但是还有一个$0需要注意,在awk中这个第0列$0中存储的内容是后面文件中的全部信息,具体例子如下:
[hadoop@hadoop001 data]$ awk '{printf $0 "\n"}' student.txt
ID Name Gender Mark
1 furong F 88
2 fengjie F 66
3 cangJK F 90
如上输出$0结果输出的是整个文件student.txt中的全部内容。
这里还有一点,在awk中内置了一个print命令,这个和printf的区别在于,输出的时候,对于每一行末尾用print输出时会加一个换行符\n,这样相比printf省事一些!!
举个实际的栗子,通过这个例子来说明为啥要awk:
需求:监控根目录下磁盘使用率,在磁盘使用率过高时发出警告。
a 获取磁盘使用率:
[hadoop@hadoop001 data]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 18G 15G 2.2G 88% /
tmpfs 3.9G 84K 3.9G 1% /dev/shm
/dev/sda1 291M 37M 240M 14% /boot
b. 提取磁盘使用率
假设我们需要监控的是/dev/sda2,则需要提取它的Use%的值,此时尝试用cut命令:
[hadoop@hadoop001 data]$ df -h | cut -f 4
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 18G 15G 2.2G 88% /
tmpfs 3.9G 84K 3.9G 1% /dev/shm
/dev/sda1 291M 37M 240M 14% /boot
[hadoop@hadoop001 data]$ df -h | cut -f 4 -d " "
上面两种尝试发现都无法提取,原因是因为df -h获取的内容中每一列中间不是制表符,而是不同个数的空格,所以用cut无法提取!
所以这里就需要使用awk来提取,用法如下:
[hadoop@hadoop001 data]$ df -h|awk '{print $5}'
Use%
88%
1%
14%
但是这里面又包含我们不需要的数据,需要进一步提取:
[hadoop@hadoop001 data]$ df -h|grep "/dev/sda2"|awk '{print $5}'|cut -f 1 -d "%"
88
以上命令就可以直接把/dev/sda2的磁盘使用率给获取到,赋予给对应变量进行判断然后发送邮件即可!
对于awk命令使用十分复杂,这里介绍部分常用的语法:
BEGIN使用场景:在所有动作和判断执行之前,执行类似于初始化操作。
假设我们要对/etc/passwd进行切分,获取第一列和第四列,显然其中分隔符应该用":",尝试用如下语句进行输出得到结果:
[hadoop@hadoop001 data]$ cat /etc/passwd | grep "/bin/bash" | awk '{FS=":"}{print $1 "\t" $4}'
root:x:0:0:root:/root:/bin/bash
roger 500
hadoop 501
mysql 27
hdfs 491
llama 488
httpfs 487
mapred 486
yarn 484
kms 483
impala 477
发现第一行并没有生效,原因是因为awk流程中第一步会先把第一行内容读取出来,读取出来第一时间赋予给了$1,此时并没有执行前面的{FS=":"}操作来指定分隔符为":",所以第一行失效了。对此,正确的语句应该是:
[hadoop@hadoop001 data]$ cat /etc/passwd | grep /bin/bash | awk 'BEGIN{FS=":"}{print $1 "\t" $4}'
root 0
roger 500
hadoop 501
mysql 27
hdfs 491
llama 488
httpfs 487
mapred 486
yarn 484
kms 483
使用BEGIN语法,使得分隔符重新设定在所有动作执行之前执行,这样就OK了。
4. sed文本替换命令
sed命令是在UNIX平台下的轻量级流编辑器,通过它可以对数据进行选取、替换、删除、新增。
sed的语法格式如下:
sed [options] '[action]' filename
option:
1. -n: 如果不加这个选项,则sed命令会把所有数据都输出到屏幕,加了之后则只会把经过sed命令处理过的行输出到屏幕;
2. -e: 如果不加这个选项,则sed命令后的action只能有一个动作,加上这个后可以允许用多个动作进行操作;
3. -i: 不加这条命令的话则sed命令修改的结果只是输出到屏幕,而不会改变数据源中的内容,而如果加上了这个选项,则会修改数据源中的数据,即文件中的内容会被彻底修改。
action:
1. a: append追加!
2. c: 行替换,用c后面的字符串替换原数据行;
3. i: 插入,是指的在当前行前插入一行或多行;
4. d: 删除,删除指定的行;
5. p: 打印,输出指定的行;
6. s: 字符串替换,用一个字符串替换另外一个字符串,格式为"行范围s/旧字符串/新字符串/g";
具体栗子如下:
打印第二行
[hadoop@hadoop001 data]$ sed -n '2p' student.txt
1 furong F 88
删除第2-4行
[hadoop@hadoop001 data]$ sed '2,4d' student.txt
ID Name Gender Mark
替换第2行内容
[hadoop@hadoop001 data]$ sed '2c wo shi tihuan hang' student.txt
ID Name Gender Mark
wo shi tihuan hang
2 fengjie F 66
3 cangJK F 90
把第2-4行的F替换为FEMALE
[hadoop@hadoop001 data]$ sed '2,4s/F/FEMALE/g' student.txt
ID Name Gender Mark
1 furong FEMALE 88
2 fengjie FEMALE 66
3 cangJK FEMALE 90
把F替换为FEMALE,并且把66分成绩替换为99(测试-e 多条sed操作)
[hadoop@hadoop001 data]$ sed -e '2,4s/F/FEMALE/g;s/66/99/g' student.txt
ID Name Gender Mark
1 furong FEMALE 88
2 fengjie FEMALE 99
3 cangJK FEMALE 90
在第2行插入一行
[hadoop@hadoop001 data]$ sed -i "2i test insert into 2p:right" test.txt
[hadoop@hadoop001 data]$ cat test.txt
hello1
test insert into 2p:right
hello2
hello3
补充个人实际案例:
在进行集群搭建时,例如redis多实例分片集群搭建时,会需要配置许多的实例,每台机器上其实配置不一样的只是port,其它配置可以保持一样,那么此时如果某一台机器配置好了四个实例的redis.conf,他们存在一个路径下/redis-sharded/xxx,那么可以直接把一台配置好的/redis-sharded/xxx直接scp到另外一台机器上,然后直接修改配置文件中的port,本人一开始是一个个配置文件vim进行修改,此时如果每台机器上的redis实例少可能还好,但是后来由于性能需要一台机器上尝试扩展是个实例,此时如果还是通过vim手动修改是十分费劲的,所以就可以用sed
修改方式1:
sed -in 's/port1/port2/g' ../redis-sharded/xxx
此时直接修改文件名xxx即可,比自己通过vim
手动编辑快多了,但是还是不方便,于是尝试是否可以多个文件一次性修改,尝试2:
sed -in 's/port1/port2/g' ../redis-sharded/xxx ../redis-sharded/xxx2 ../redis...
这样就可以直接一条命令搞定,但是后面这些所有路径都是类似的,那么我们是否可以尝试类似正则的形式直接模糊匹配../redis-sharded/
路径下的所有.conf
文件修改呢,这样就不需要敲很多的路径了,尝试一下:
sed -in 's/port1/port2/g' ../redis-sharded/*.conf
尝试一下果断成功,这应该就是最方便没有之一的方式了吧!所以还是得多使用多尝试的,不是么~