【Shell】shell 处理文本/日志(一行一行读文本-特别注意for)

时间:2025-04-08 17:20:27

目录

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

AWK输出某几列

一行一行读文本

awk  遍历文件行处理

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

shell 删除每一行前面的数字

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

在每一行后面加字符串



作者:bandaoyu  文章持续更新,地址:/bandaoyu/article/details/103190949 



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

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

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

AWK输出某几列

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

[root@SH]# cat  
 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
  • 可以awk '{print $1,$2,$3,$4,$5}
  • 另外一种实现方法awk '{NF-=2}1',这里的1换成别的数字也可以,NF-=2表示倒数第二列
  • AWK输出某几列 - n0n1的个人空间 - OSCHINA - 中文开源技术交流社区

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 >> 
#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 >> 

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 >> 
	#echo $datemk $CpuMemStat
done 

	sleep 1s
done

一行一行读文本

for 方法

一行一行读,如果用for 要重新设置分割符,因为in操作符以任意空白字符作为分割, 而read line是以回车符作为分割。

如:

有一文本文件如下,每行有两个字符串/空格分开。


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

for line in `cat `
do
echo $line
done


得到结果如下:

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

解决方法:重新设置分割符

IFS=$'\n' # 定义分割符
# for i in $(cat file) # better
# for i in $(<file) # in bash
for i in `cat file`
do
echo "$i"
done

while 方法


============
while read line
do 
echo $line
done 

运行得到结果如下:

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

while注意事项:

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

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

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

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

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

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

原文链接:/weixin_31201737/article/details/113045998

实战:


 -5        10.47839 root ssdpool                                        
-25        10.47839     rack                               
-28         3.49280         host                         
 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                         
 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                         
 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脚本 ,我给它参数61(或者63或64), 它就读取host 下面的行文字的第一个字段,并逐一输出log+字段,直至遇到下一个host rdma 停止。

如:  61

输出:






如:  63




脚本

awk -v flag=0 '
/host rdma'$1'/ {flag=1; next}
flag == 1 && /host rdma/ {flage=0; exit}
flag == 1 {print "log"$1".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真是神器啊_王后浪的博客-****博客

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

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

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

strA=""
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]* *//'  

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

#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/

在每一行后面加字符串

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

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