linux shell命令のcut、printf、awk、sed字符操作命令用法

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

尝试一下果断成功,这应该就是最方便没有之一的方式了吧!所以还是得多使用多尝试的,不是么~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值