【Shell】shell 处理文本/日志(一行一行读文本-必须用while不能用for)

目录

shell 获取结果中的第n列,第n行

AWK输出某几列

awk  遍历文件行处理

shell 脚本 遍历文件 找出包含特定字符串的行数/行

shell 删除每一行前面的数字

在匹配字符后面追加字符串

在每一行后面加字符串



作者:bandaoyu  文章持续更新,地址:https://blog.csdn.net/bandaoyu/article/details/103190949 



shell 获取结果中的第n列,第n行

ls -l | awk '{print $5}' | sed -n '2p'

awk 是很实用的文本处理命令,print 到后带的是你要获取第几列,sed -n 是指定第几行。

AWK输出某几列

有这样一个文本,需要截取前5行

[root@SH]# cat test.txt 
 2      3651415576       940761              0            0 0000000000000000
 3      3532686312       939551              0            0 0000000000000000
 4      3873453656       984285              0            0 0000000000000000
 5      3884604640       970761              0            0 0000000000000000
 6      2116906224       493295              0            0 0000000000000000
 7      1760674752       480700              0            0 0000000000000000
 8               0            0       29979808         6002 0000000000000000
 10              0            0        3299944         1433 0000000000000000
 11              0            0     2199434640       312565 0000000000000000

linux下统计某个进程的CPU占用和内存使用

#!/bin/bash
# while loop
 
CpuMemStat=""
datemk=""
while true
do
CpuMemStat=` ps aux |grep -i server |grep redis |grep -v py`
datemk=`date "+%Y-%m-%d %H:%M:%S"`
echo $datemk $CpuMemStat >> result.txt
#echo $datemk $CpuMemStat
sleep 20s
done

上面的遇到CpuMemStat结果是多行的就歇菜了,改成

#!/bin/bash
# while loop 
CpuMemStat=""
datemk=""

CpuMemStat=`ps aux |sed -n '1p'|awk '{print $1,$2,$3,$4,$5}'`
datemk=`date "+%Y-%m-%d %H:%M:%S"`
echo $datemk $CpuMemStat >> result.txt

while true
do
	#CpuMemStat=` ps aux |grep -i redis-server|awk '{print $1,$2,$3,$4,$5}'`
    datemk=`date "+%Y-%m-%d %H:%M:%S"`


ps aux |grep -i redis-server|awk '{print $1,$2,$3,$4,$5}'|while read line
do
 echo $line
 echo $datemk $line >> result.txt
	#echo $datemk $CpuMemStat
done 

	sleep 1s
done

(一行一行读,不能用for 必须用while,因为in操作符以任意空白字符作为分割, 而read line是以回车符作为分割。

注意 | 管道会起子进程,子进程内的变量无法传到外面,例如:

[liuhao@slave04 ~]$ cat test.sh 
#! /bin/sh

x=1
echo "adasd" | while read line
do
    x=2 
done
echo $x

运行结果是
[liuhao@slave04 ~]$ sh test.sh 
1
原因

原来是因为管道|创建了新的子进程,而子进程是在独立的进程空间(Context)运行了. 需要跟父进程通信的话, 得使用进程间通信机制. 不是简单的变量问题。

有一文本文件如下,每行有两个字符串/空格分开。
$ cat list.txt 
Gly G
Ala A
Val V
Leu L
Ile I
Phe F


for line in `cat list.txt`
do
echo $line
done
得到结果如下:

Gly
G
Ala
A
Val
V
Leu
L
Ile
I
Phe
F

============
while read line
do 
echo $line
done list.txt

运行得到结果如下:

Gly G
Ala A
Val V
Leu L
Ile I
Phe F

awk  遍历文件行处理


awk基本语法如下:

awk 'BEGIN{//begin code }            pattern1{//pattern1 code}             pattern2{//pattern2 code}          END{//end code }'

BEGIN部分的代码,最先执行

然后循环从管道中读取的每行文本,如果匹配pattern1 ,则执行pattern1 code的代码,匹配pattern2,则执行pattern2 code代码
最后,执行END部分的代码end code

如下所示,分别求奇数行与偶数行的和:
$ seq 1 5
1
2
3
4
5

$ seq 1 5|awk 'BEGIN{print "odd","even"}    NR%2==1{odd+=$0}    NR%2==0{even+=$0}    END{print odd,even}'
odd even
9 6

原文链接:https://blog.csdn.net/weixin_31201737/article/details/113045998

实战:

info.txt


 -5        10.47839 root ssdpool                                        
-25        10.47839     rack rack.ssdpool                               
-28         3.49280         host rdma61.ssdpool                         
 18   ssd   0.87320             osd.18              up  1.00000 1.00000 
 21   ssd   0.87320             osd.21              up  1.00000 1.00000 
 24   ssd   0.87320             osd.24              up  1.00000 1.00000 
 28   ssd   0.87320             osd.28              up  1.00000 1.00000 
-31         3.49280         host rdma63.ssdpool                         
 20   ssd   0.87320             osd.20              up  1.00000 1.00000 
 22   ssd   0.87320             osd.22              up  1.00000 1.00000 
 25   ssd   0.87320             osd.25              up  1.00000 1.00000 
 27   ssd   0.87320             osd.27              up  1.00000 1.00000 
-34         3.49280         host rdma64.ssdpool                         
 19   ssd   0.87320             osd.19              up  1.00000 1.00000 
 23   ssd   0.87320             osd.23              up  1.00000 1.00000 
 26   ssd   0.87320             osd.26              up  1.00000 1.00000 
 29   ssd   0.87320             osd.29            down        0 1.00000 

写一个shell脚本 run.sh,我给它参数61(或者63或64), 它就读取host rdma61.ssdpool下面的行文字的第一个字段,并逐一输出log+字段,直至遇到下一个host rdma 停止。

如: run.sh 61

输出:

log18.txt
log21.txt
log24.txt
log28.txt

如: run.sh 63

log20.txt
log22.txt
log25.txt
log27.txt

脚本

awk -v flag=0 '
/host rdma'$1'/ {flag=1; next}
flag == 1 && /host rdma/ {flage=0; exit}
flag == 1 {print "log"$1".txt"}
' info.txt
 

-v flag=0 # 设置变量flag=0

/host rdma'$1'/ {flag=1; next}                   #匹配到host rdma'$1'执行flag=1; next,netx 表示不匹配本文本行后面的内容,直接跳到下一行文本

flag == 1 && /host rdma/ {flage=0; exit}  #flag == 1 且匹配到host rdma,则执行{flage=0; exit} ,exit 退出结束

flag == 1 {print "log"$1".txt"}                  #flag == 1 且匹配到host rdma,则执行print "log"$1".txt"

更多:awk输出指定行_原来awk真是神器啊_王后浪的博客-CSDN博客

shell 脚本 遍历文件 找出包含特定字符串的行数/行

#!/bin/bash
 
printf "*************************************\n"
a=0       
while read line
do        
 [[ $line =~ "css" ]] && ((a++))  
done < test.txt 
echo $a
#!/bin/bash

ceph osd tree |& grep -E "ssd|ssdpool" > osd_nodes_id.txt

strA="rdma63.ssdpool"
while read -r line
do
echo ${line}
if [[ ${line} =~ ${strA} ]];
then
  echo "包含"
fi
done < osd_nodes_id.txt

shell 删除每一行前面的数字

例如:

1      haha

3      hoho

512  嘿嘿

sed -i 's/^[0-9]* *//'   a.txt

在匹配字符后面追加字符串

#use command 'sed' to add A behind pattern :sed 's/pattern/&A/' filename  在pattern 字符的后面追加(注意符号要转译)


#例如:

#sed -i 's/\[mysqld\]/&\n \
#wait_timeout=2073600\n \
#interactive_timeout=2073600\n \
#bulk_insert_buffer_size=16M\n \
#max_allowed_packet=16M\n/'  /etc/my.cnf

在每一行后面加字符串

#sed -i 'xxxx' dsc.cnf   在 dsc.cnf的每一行后面加'xxxx'

#ehco "xxxx" dsc.cnf  在 dsc.cnf的后面加'xxxx' ,换行的地方可以直接按回车

posted on 2022-10-04 01:27  bdy  阅读(18)  评论(0编辑  收藏  举报

导航