1、用shell脚本把一个文本文档中只有一个数字的行给打印处理;准备一下test.txt文件用来测试,内容如下:
[root@localhost_001 ~]# cat test.txt
aaa:1:abcde:sdfsd:sdfasd
bbb:22:adsafsadfsdaf:sdafsd
bbb:2:233:3sdfsdf
分析:既然要只有一个数字的行,也就是要针对每一行去逐行去处理,此处用到了for循环或者while分别处理每一行;
判断某行有一个数字,可以这样来实现: 过滤出非0-9的内容替换为空,并统计字符长度; sed 's#[^0-9]##g'|wc -L
[root@localhost_001 ~]# sed -n '1'p test.txt|sed 's#[^0-9]##g'|wc -L
1
[root@localhost_001 ~]# sed -n '2'p test.txt|sed 's#[^0-9]##g'|wc -L
2
[root@localhost_001 ~]# sed -n '3'p test.txt|sed 's#[^0-9]##g'|wc -L
5
首先统计出文件的行数, wc -l test.txt|awk '{print $1}'
[root@localhost_001 ~]# wc -l test.txt
3 test.txt
[root@localhost_001 ~]# wc -l test.txt|awk '{print $1}'
3
然后使用for 来循环打印出每一行,并计算每一行字符长度:
for a in `seq 1 $n`;do n1=`sed -n 'a'p /root/test.txt|sed 's#[^0-9]##g'|wc -L`
再用 if 来判断是否等于 1,等于则打印,符合题意要求; if [ $n1 -eq 1 ] then sed -n "a"p /root/test.txt
脚本内容如下:执行后只有第一行有一个数字,故第一行符合要求;
[root@localhost_001 ~]# cat 36.sh
#!/bin/bash
f=/root/test.txt
n=`wc -l $f|awk '{print $1}'`
for a in `seq 1 $n`
do
n1=`sed -n "$a"p $f|sed 's#[^0-9]##g'|wc -L`
if [ $n1 -eq 1 ]
then
sed -n "$a"p $f
fi
done
执行脚本:
[root@localhost_001 ~]# sh 36.sh
aaa:1:abcde:sdfsd:sdfasd
其实这个脚本还有第二种方式:使用while read line do done 的方式逐行处理;
[root@fenye2019 shell]# cat 36.1.sh
#!/bin/bash
while read line
do
n=`echo $line|sed 's#[^0-9]##g'|wc -L`
if [ $n -eq 1 ]
then
echo $line
fi
done < test.txt
执行脚本:
[root@fenye2019 shell]# sh 36.1.sh
aaa:1:abcde:sdfsd:sdfasd
2、用一个shell脚本,实现日记的切割、归档功能; logrotate
要求日记每天 来归档,1.log,第二天变成了1.log.1 第三天变成了1.log.2 第四天变成了1.log.4 第五天变成1.log.5 只保存5个,后面的删除;
首先在创建一个目录,并在目录下创建对应的几个文件: 1.log 1.log.1 1.log.2 1.log.3 1.log.4 1.log.5
前提在最后还需要重启服务,以保证可以生成新的1.log;
[root@fenye2019 shell]# ls /data/logs/
1.log 1.log.1 1.log.2 1.log.4 1.log.5
脚本内容如下: 执行后还需要重启服务,才会生成新的1.log文件;
这个脚本需要倒着推,先处理1.log.5,最后处理1.log.1,先判断1.log.5如果存在的话则删除1.log.5,然后循环遍历为倒序,从5开始循环,然后是4,然后是3,最后是2,之所以不循环1,是因为改名字的是1.log,而不是1.log.0。
在每次把前一个文件(1.log.1)改名成后一个(1.log.2)文件时,最后检测一下这个文件是否存在,如果存在则先删除掉,这样才能顺利把前面文件改名为后面文件,所有使用一个函数mv_log最合适;
[root@fenye2019 shell]# cat 37.sh
#!/bin/bash
cd /data/logs
log=1.log
mv_log()
{
[ -f $1 ] && mv $1 $2
}
[ -f 1.log.5 ] && rm -f 1.log.5
for i in `seq 4 -1 1`
do
j=$[$i+1]
mv_log $log.$i $log.$j
done
mv 1.log 1.log.1
执行脚本:
[root@fenye2019 shell]# sh 37.sh
[root@fenye2019 shell]# ls /data/logs/
1.log.1 1.log.2 1.log.3 1.log.5
如图脚本所示: seq 4 -1 1 会倒序输出;
[root@fenye2019 shell]# seq 4 -1 1
4
3
2
1
3、写一个shell脚本,把192.168.149.0/24网段在线的IP和不在线都列出来,并输出到up.list和down.list两个文件;
分析:ping一个网段时,前面部分(192.168.149)是一样的,最后一位可以用变量代替;
然后可以用ping选项,ping通则这个主机是在线的;ping -c2 -w2 192.168.149.129 表示ping两个包,每个表间隔2秒;
然后以判断返回值的方式来查看是否可以ping 通; if [ $? -eq 0 ] then fi
脚本内容如下:
[root@localhost_002 shell]# cat 38.sh
#!/bin/bash
for i in `seq 1 254`
do
ping -w2 192.168.149.$i >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "192.168.149.$i" >> /tmp/ip_up.list
else
echo "192.168.149.$i" >> /tmp/ip_down.list
fi
done
执行脚本:
[root@localhost_002 shell]# sh 38.sh
[root@localhost_002 shell]# cat /tmp/ip_up.list
192.168.149.2
192.168.149.130
192.168.149.135
[root@localhost_002 shell]# head -n3 /tmp/ip_down.list
192.168.149.1
192.168.149.2
192.168.149.3
或者可以通过不判断返回值,直接在for循环里用if 来判断即可,如下 :
#!/bin/bash
for i in `seq 1 254`
do
if ping -c2 -W2 192.168.149.$i >/dev/null 2>/dev/null
then
echo "192.168.149.$i" >> /tmp/ip_up.list
else
echo "192.168.149.$i" >> /tmp/ip_down.list
fi
done
4、一个shell脚本,检查指定的shell脚本是否有错误,若有错误,首先显示错误信息,然后提示用户输入q或者Q退出脚本,输入其他内容则用vim打开这个脚本;
分析:要检查脚本是否有错误,使用 sh -n 脚本名 来测试; sh -n 39.sh
提示用户输入: read -p "please input q/Q exit, or others to edit it by vim:" n
需要考虑到 如果变量为 空时, 也是使用 vim 来打开这个文件; if [ -z $n ] then vim $i fi 注: $i 表示第一个参数;
然后需要判断 $n 是否等于 q 或者 Q,然后执行相应操作:
if [ $n == "q" -o $n == "Q" ] 等同于 if [ $n == "q" ] || [ $n =="Q" ]
脚本内容如下:首先定义有语法错误的脚本:然后用来测试:
[root@fenye2019 shell]# cat 1.sh
#!/bin/bash
#打印出1-50的随机数10次;
for i in `seq 1 10`
do
echo $[RANDOM]
#done
[root@fenye2019 shell]# cat 39.sh
#!/bin/bash
sh -n 2>/tmp/trr
if [ $? -ne 0 ]
then
cat /tmp/trr
read -p "please input q/Q to exit:" n
if [ -z "$n" ]
then
vim $1
exit
fi
if [ $n == q ] || [ $n == Q ]
then
exit
else
vim $1
exit
fi
else
echo "脚本$1没有语法错误"
fi
执行脚本: 脚本1.sh有语法错误,脚本31.sh没有语法错误;
[root@fenye2019 shell]# sh 39.sh 1.sh
1.sh: line 7: syntax error: unexpected end of file
please input q/Q to exit:q
[root@fenye2019 shell]# sh 39.sh 31.sh
脚本31.sh没有语法错误
注释:在shell脚本中 vim 一个文件,虽然可以进入到这个文件里,但当退出这个文件后,脚本依然会继续执行,所有在 vim $1 命令后面要加上 exit;
5、输入一串随机数字,然后按千分位输出;
比如输出:123456789 输出为123.345.769
分析:用户输入: read -p "please input a number:" n 来实现:
需要判断用户输入的是否是纯数字,如果不是,则重新输入: n2=`echo $n|sed '[0-9]'` if [ -n $n2 ] then echo "你输入不是数字,重新输入" continue
脚本内容:
[root@fenye2019 shell]# cat 40.sh
#!/bin/bash
n=`echo $1|wc -L`
for d in `echo $1|sed 's/./& /g'`
do
n2=$[$n%3]
if [ $n2 -eq 0 ]
then
echo -n ",$d"
else
echo -n "$d"
fi
n=$[$n2-1]
done|sed 's/^,//g'
echo
执行:
[root@fenye2019 shell]# sh 40.sh 1234567
1,234,567
注释:默认字符串分割是没有空格的,那么如何变成 以 空格分割 字符串呢?如下:
[root@fenye2019 shell]# echo "1234"
1234
[root@fenye2019 shell]# echo "1234"|sed 's#.#& #g'
1 2 3 4
然后每一次除以 3 取余数,如果余数为 0 ,则表示可以整除,则用 if 判断,并在前面加,逗号,如果不为 0 ,则不在前面加,逗号;
因为我们是倒序的,还需要在重新计算 n, n=$[$n-1]
最后还需要加上 echo 换行符才可以的;
如果添加的参数 刚刚是 9 位,则最前面还是会显示出来一个 ,逗号,如下:
[root@fenye2019 shell]# sh 40.sh 123523424
,123,523,424
可以在最后在处理一下,过滤到前面的,逗号, done |sed 's#^,##g'