【Shell】shell 处理文本/日志(一行一行读文本-必须用while不能用for)
目录
作者: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
- 可以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 >> 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' ,换行的地方可以直接按回车