注意 : 在VIM中使用set paste格式化vim,再粘贴内容,格式就不会乱
关系运算符
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
-lt #表示小于
-gt #表示大于
-eq #表示等于
-qw #表示是否
-ne #表示非、不等于
-ge #表示 大于等于
-b #表示判断是不是
字符串运算符
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否为0,不为0返回 true。 | [ -n "$a" ] 返回 true。 |
$ | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
正则表达式元字符
-
特殊的元字符
-
扩展的正则表达式
Linux 教程
Linux 教程Linux 简介Linux 安装Linux 系统启动过程Linux 系统目录结构Linux 忘记密码解决方法Linux 远程登录Linux 文件基本属性Linux 文件与目录管理Linux 用户和用户组管理Linux 磁盘管理Linux vi/vimlinux yum 命令
Shell 教程
Shell 教程Shell 变量Shell 传递参数Shell 数组Shell 运算符Shell echo命令Shell printf命令Shell test 命令Shell 流程控制Shell 函数Shell 输入/输出重定向Shell 文件包含
Linux 参考手册
Linux 命令大全Nginx 安装配置MySQL 安装配置
Shell printf 命令
上一章节我们学习了 Shell 的 echo 命令,本章节我们来学习 Shell 的另一个输出命令 printf。
printf 命令模仿 C 程序库(library)里的 printf() 程序。
printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好。
printf 使用引用文本或空格分隔的参数,外面可以在 printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。默认 printf 不会像 echo 自动添加换行符,我们可以手动添加 \n。
printf 命令的语法:
printf format-string [arguments...]
参数说明:
- format-string: 为格式控制字符串
- arguments: 为参数列表。
实例如下:
$ echo "Hello, Shell" Hello, Shell $ printf "Hello, Shell\n" Hello, Shell $
接下来,我来用一个脚本来体现printf的强大功能:
#!/bin/bash # author:菜鸟教程 # url:www.runoob.com printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543 printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
执行脚本,输出结果如下所示:
姓名 性别 体重kg 郭靖 男 66.12 杨过 男 48.65 郭芙 女 47.99
%s %c %d %f都是格式替代符
%-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
%-4.2f 指格式化为小数,其中.2指保留2位小数。
更多实例:
#!/bin/bash # author:菜鸟教程 # url:www.runoob.com # format-string为双引号 printf "%d %s\n" 1 "abc" # 单引号与双引号效果一样 printf '%d %s\n' 1 "abc" # 没有引号也可以输出 printf %s abcdef # 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用 printf %s abc def printf "%s\n" abc def printf "%s %s %s\n" a b c d e f g h i j # 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替 printf "%s and %d \n"
执行脚本,输出结果如下所示:
1 abc 1 abc abcdefabcdefabc def a b c d e f g h i j and 0
printf的转义序列
序列 | 说明 |
---|---|
\a | 警告字符,通常为ASCII的BEL字符 |
\b | 后退 |
\c | 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略 |
\f | 换页(formfeed) |
\n | 换行 |
\r | 回车(Carriage return) |
\t | 水平制表符 |
\v | 垂直制表符 |
\\ | 一个字面上的反斜杠字符 |
\ddd | 表示1到3位数八进制值的字符。仅在格式字符串中有效 |
\0ddd | 表示1到3位的八进制值字符 |
31、题目要求 :获取网卡ip、 获取网卡ip显示颜色
提示用户输入网卡的 名字,然后我们用脚本输出网卡的ip,需要考虑下面问题:
- 输入的字符不符合网卡名字规范,怎么应对。
- 名字符合规范,但是根本就没有这个网卡又怎么应对。
参考答案
#!/bin/bash
ip add |awk -F ': ' '$1 ~ "^[1-9]" {print $2}' > /tmp/eth.list
while :
do
eths=`cat /tmp/eth.list |xargs`
read -p "Please input a if name(The eths is `echo -e "\033[31m$eths\033[0m"`): " eth
if [ -z "$eth" ]
then
echo "Please input a if name."
continue
fi
if ! grep -qw "$eth" /tmp/eth.list
then
echo "The if name is error."
continue
else
break
fi
done
if_ip()
{
ip add show dev $1 |grep ' inet ' |awk '{print $2}'|awk -F '/' '{print $1}' >/tmp/$1.txt
n=`wc -l /tmp/$1.txt|awk '{print $1}'`
if [ $n -eq 0 ]
then
echo "There is no ip address on the eth."
else
echo "The ip addreess is:"
for ip in `cat /tmp/$1.txt`
do
echo -e "\033[33m$ip\033[0m"
done
fi
}
if_ip $eth
实例 :
[root@localhost ~]# # ip add # 查看机器上所有的网卡
[root@localhost ~]# # ip add |awk -F ': ' '$1 ~ "^[1-9]" {print $2}' #查看所有的网卡列表
[root@localhost ~]# # ip add show dev ens33 | grep ' inet ' |awk '{print $2}' #获取ens33网卡的IP,并精准截取IP所在的第二行。/24表示是IP地址的netmask网段
输入网卡的名字 ,运行脚本,查看结果,
如果输入了。错的网卡名字,会提示网卡名字错误。输入正确的网卡名字,就直接显示IP地址,然后退出。
未添加颜色,执行脚本之后,显示的结果。
注意 :
cat /tmp/eth.list |xargs #在脚本中表示列出所有的网卡的名字
[root@localhost ~]# echo "Please input a if name(The eths is 'cat /tmp/eth.list|xargs')" #查看网卡列表中的eth网卡
if [ -z "$eth" ] #表达的含义,是如果eth是空的,就提示用户 : Please input a if name.
if ! grep -qw "$eth" /tmp/eth.list #表达的含义,是如果eth是不在/tmp/eth.list 文件中,就提示用户 : The if name is error.
if_ip #函数的名字
ip add show dev $1 |grep ' inet ' |awk '{print $2}'|awk -F '/' '{print $1}' >/tmp/$1.txt #显示IP网卡的IP地址,并把输出的结果存入/tmp/$1.txt临时文件中 ,$1表示第一个参数。
wc -l /tmp/$1.txt|awk '{print $1} #先统计/tmp/$1.txt临时文件中的行数。
if [ $n -eq 0 ] #如果eq等于0,那么提示用户 “There is no ip address on the eth.”
31.2 获取网卡ip显示颜色
案例
echo显示带颜色,需要使用参数-e
格式如下 :
echo -e "\033"[字背景颜色;文字颜色m字符串\033[0m
例如 :
echo -e"\033[41;37m TonyZhang \033[0m"
其中41的位置代表底色,37的位置是代表字的颜色
注 :
1、字背景颜色和文字颜色之间是英文的”""”
2、文字颜色后面有个m
3、字符串前后可以没有空格,如果有的话,输出也是同样有空格
例子 :
echo -e "/033[30m 黑色字 \033[0m"
echo -e "/033[31m 红色字 \033[0m"
echo -e "/033[30m 绿色字 \033[0m"
echo -e "/033[30m 黄色字 \033[0m"
echo -e "/033[30m 蓝色字 \033[0m"
echo -e "/033[30m 紫色字 \033[0m"
echo -e "/033[30m 蓝色字 \033[0m"
echo -e "/033[30m 白色字 \033[0m"
echo -e "/033[30m 黑底白色字 \033[0m"
echo -e "/033[30m红底 白字 \033[0m"
echo -e "/033[30m 绿底白字 \033[0m"
echo -e "/033[30m 黄底白字 \033[0m"
echo -e "/033[30m 蓝底白字 \033[0m"
为网卡的名称显示颜色。
#!/bin/bash
ip add |awk -F ': ' '$1 ~ "^[1-9]" {print $2}' > /tmp/eth.list
while :
do
eths=`cat /tmp/eth.list |xargs`
read -p "Please input a if name(The eths is '/tmp/eth.list|xargs'): " eth
if [ -z "$eth" ]
then
echo "Please input a if name."
continue
fi
if ! grep -qw "$eth" /tmp/eth.list
then
echo "The if name is error."
continue
else
break
fi
done
if_ip()
{
ip add show dev $1 |grep ' inet ' |awk '{print $2}'|awk -F '/' '{print $1}' >/tmp/$1.txt
n=`wc -l /tmp/$1.txt|awk '{print $1}'`
if [ $n -eq 0 ]
then
echo "There is no ip address on the eth."
else
echo "The ip addreess is:"
`cat /tmp/$1.txt
fi
}
if_ip $eth
添加颜色,执行脚本之后,显示的结果。
32、题目要求 : 列出目录内容
写一个脚本,实现如下功能:
- 脚本可以带参数也可以不带
- 参数可以有多个,每个参数必须是一个目录
- 脚本检查参数个数,若等于0,则列出当前目录本身,否则显示每个参数包含的子目录。
【核心要点】
$#参数个数
test -d filename #
find $d -type d #把当前文件下的文件全部列出来
参考答案
#!/bin/bash
if [ $# -eq 0 ]
then
echo "当前目录下的文件是:"
ls .
else
for d in $@
do
if [ -d $d ]
then
echo "目录$d下有这些子目录:"
find $d -type d
else
echo "并没有该目录:$d"
fi
done
fi
实例 :
查看当前目录下的文件
显示tmp和/usr/local目录下的文件
33、题目要求 : 下载文件
定义一个shell函数,能接受两个参数,满足以下要求:
- 第一个参数为URL,即可下载的文件,第二个参数为目录,即下载后保存的位置
- 如果用户给的目录不存在,则提示用户是否创建,如果创建就继续执行,否则,函数返回一个51的错误值给调用脚本
- 如果给的目录存在,则下载文件,下载命令执行结束后测试文件下载成功与否,如果成功,则返回0给调用脚本,否则,返回52给调用脚本
参考答案
#!/bin/bash
if [ $# -ne 2 ]
then
echo "你必须要输入两个参数,第一个参数是网址,第二个参数是目录."
exit 1
fi
if [ ! -d $2 ]
then
while :
do
echo "你输入的第二个参数,并不是一个存在的目录。是否要创建该目录呢?(y|n): "c
case $c in
y|Y)
mkdir -p $2
;;
n|N)
exit 51
;;
*)
echo "请输入y或者n."
continue
;;
esac
done
else
cd $2
wget $1
if [ $? -eq 0 ]
then
exit 0
else
echo "下载失败."
exit 52
fi
fi
实例 :
运行脚本,得到结果是1,说明脚本没问题。返回52给调用脚本,给的目录不存在,则下载文件失败,
脚本解析失败,原因后面没有两个参数,
输入两个参数,第一个参数是网址,第二个参数是目录时,就解析成功了。
查看下载的文件
注意 :
if [ $# -ne 2 ] #如果参数不等于2,提示 : 你必须要输入两个参数,第一个参数是网址,第二个参数是目录.
if [ ! -d $2 ] #如果$2是一个不存在的目录,提示 :你输入的第二个参数,并不是一个存在的目录。是否要创建该目录呢?(y|n):
mkdir -p $2 #如果客户输入了y或者Y,创建这个目录。如果输入N|n,直接退出。
cd $2
wget $1 #表示如果没有,就cd切换到$2,然后wegt下载
if [ $? -eq 0 ] #如果$?等于0,表示下载成功就退出,否则就是下载失败。
报错原因 : 未安装命令。解决办法 : yum install -y wget
34、题目要求 : 猜数字
写一个shell脚本,能实现如下需求:
- 执行脚本后,提示输入名字(英文的,可以是大小写字母、数字不能有其他特殊符号),然后输出一个随机的0-99之间的数字,脚本并不会退出,继续提示让输入名字
- 如果输入相同的名字,输出的数字还是第一次输入该名字时输出的结果
- 前面已经输出过的数字,下次不能再出现
- 当输入q或者Q时,脚本会退出。
参考答案
#!/bin/bash n=$[$RANDOM%101] while : do read -p "请输入一个0-100的数字:" n1 if [ -z "$n1" ] then echo "必须要输入一个数字。" continue fi n2=`echo $n1 |sed 's/[0-9]//g'` if [ -n "$n2" ] then echo "你输入的数字并不是正整数." continue else if [ $n -gt $n1 ] then echo "你输入的数字小了,请重试。" continue elif [ $n -lt $n1 ] then echo "你输入的数字大了,请重试。" continue else echo "恭喜你,猜对了!" break fi fi done
实例 :
获取一个随机的数字
获取一个100以内的随机数字
运行0-99的脚本,输入一个正确的随机数字,就结束了。
35.1、题目要求 : 根据名字得数字
写一个shell脚本,能实现如下需求:
- 执行脚本后,提示输入名字(英文的,可以是大小写字母、数字不能有其他特殊符号),然后输出一个随机的0-99之间的数字,脚本并不会退出,继续提示让输入名字
- 如果输入相同的名字,输出的数字还是第一次输入该名字时输出的结果
- 前面已经输出过的数字,下次不能再出现
- 当输入q或者Q时,脚本会退出。
参考答案
#!/bin/bash f=/tmp/user_number.txt while : do read -p "Please input a username: " u u1='echo $u|sed 's/[a-zA-Z0-9]//g'' if [ -n "$u1" ] then echo "你输入的用户名不符合规范,正确的用户名应该是大小写字母和数字的组合" continue else if [ -f $f ] then u_n=`awk -v uu=$u '$1==uu {print $2}' $f` if [ -n "$u_n" ] then echo "用户$u对应的数字是:$u_n" else n=$[$RAMDOM%100] echo "用户$u对应的数字是 : $n" echo $u $n >> $f fi else n=$[$RAMDOM%100] echo "用户$u对应的数字是:$n" echo $u $n >> $f fi fi done
实例 :
查看运行的结果,/tmp/user_number.txt文件没有创建。
当第二次执行脚本时,/tmp/user_number.txt就创建了。输入q或者大写的 Q,退出 运行的脚本。不建议使用ctrl +c.
注意 :
u_n #u_n的值为1
if [ -n "$u_n" ] #如果u_n不为空,那么$u对应的变量就是$u_n ;否则,重新创造一个随机数。
`echo $u|sed 's/[a-zA-Z0-9]//g'` #如果输入u的值,是空的,说明用户输入的名字是对的
-n "$u1" #如果输入的不为空,。提示 “你输入的用户名不符合规范,正确的用户名应该是大小写字母和数字的组合”
"$u $n" >>$f #将用户名和对应的数字,记录到/tmp/user_number.txt文件中
awk '{print $2}' $f|grep -qw $n #查找/tmp/user_number.txt文件中第二段截取出来,
u_n=`awk -v uu=$u '$1==uu {print $2}' $f` #求用户名中的行数,并截取/tmp/user_number.txt文件中第二段
35.2 根据名字得数字优化
参考答案
#!/bin/bash f=/tmp/user_number.txt j_n() { while : do n=$[RANDOM%100] if awk '{print $2}' $f|grep -qw $n then continue else break fi done } while : do read -p "Please input a username: " u if [ -z "$u" ] then echo "请输入用户名." continue fi if [ $u == "q" ] || [ $u == "Q" ] then exit fi u1=`echo $u|sed 's/[a-zA-Z0-9]//g'` if [ -n "$u1" ] then echo "你输入的用户名不符合规范,正确的用户名应该是大小写字母和数字的组合" continue else if [ -f $f ] then u_n=`awk -v uu=$u '$1==uu {print $2}' $f` if [ -n "$u_n" ] then echo "用户$u对应的数字是:$u_n" else j_n echo "用户$u对应的数字是:$n" echo "$u $n" >>$f fi else j_n echo "用户$u对应的数字是:$n" echo $u $n >> $f fi fi done
注意 :
if awk '{print $2}' $f|grep -qw $n #表示查看/tmp/user_number.txt文件第二端,是否已经出现了$n随机数?
36、题目要求 : 一个数字的行
系统logrotate工具,可以完成日志切割、归档。写一个shell脚本实现类似的归档功能。 举例: 假如服务的输出日志是1.log,要求每天归档一个,1.log第二天就变成1.log.1,第三天1.log.2, 第四天 1.log.3 一直到1.log.5。
参考答案
#!/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
实例 :
统计行中出现的数字
注意 :
echo $line |sed 's/[^0-9]//g' |wc -L #统计所有的行,将所有的非数字全部删除,只剩下数字,并计算数字的个数。
37、题目要求 : 日志切割归档
系统logrotate工具,可以完成日志切割、归档。写一个shell脚本实现类似的归档功能。 举例: 假如服务的输出日志是1.log,要求每天归档一个,1.log第二天就变成1.log.1,第三天1.log.2, 第四天 1.log.3 一直到1.log.5。
参考答案
#!/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
实例 :
创建/data/logs目录 , 然后在1.log里面写入111
往2.log日志里面写入222,按照顺序,依次在日志里面写入对应的数字,如:3.log里面写333.
查看脚本是否有问题,在1.log日志文件中写入000.然后执行 “cat *”命令,查看运行结果。应该系统日志只有两个,所以显示的结果到222,就结束了。
注意 :
log=1.log #log是定义的变量
mv_log() #定义的函数
[ -f $1 ] && mv $1 $2 #如果$1存在,就把$1改成$2
[ -f 1.log.5 ] && rm -f 1.log.5 #如果1.log.5存在,就删除1.log.5
38、题目要求 : 查找在线IP
写一个shell脚本,把192.168.0.0/24网段在线的ip列出来。
参考答案
#!/bin/bash
for i in `seq 1 254`
do
if ping -c 2 -W 2 192.168.0.$i >/dev/null 2>/dev/null
then
echo "192.168.0.$i 是通的."
else
echo "192.168.0.$i 不通."
fi
done
实例 :
有两个IP地址,测试一个通的,返回ok,一个不通的,什么都不返回。
执行脚本,查看脚本运行的结果。因为这个网段,不通,所以全部都不通
注意 :
for i in `seq 1 254` #ping的IP地址范围1-254
if ping -c 2 -W 2 192.168.0.$i >/dev/null 2>/dev/null #把能ping通的IP地址写入到/dev/nul,错误的也写入/dev/null 。-c 2表示ping两次,-W 2 表示ping的时间为两秒
39、题目要求 : 检查脚本错误
写一个shell脚本,检查指定的shell脚本是否有语法错误,若有错误,首先显示错误信息,然后提示用户输入q或者Q退出脚本,输入其他内容则直接用vim打开该shell脚本。
参考答案
#!/bin/bash
sh -n $1 2>/tmp/sh.err
if [ $? -ne 0 ]
then
cat /tmp/sh.err
read -p "请输入q/Q退出脚本。" c
if [ -z "$c"]
then
vim $1
exit 0
fi
if [ $c == q ] || [ $c == Q ]
then
exit 0
else
vim $1
exit 0
fi
else
echo "脚本$1没有语法错误."
fi
实例 :
脚本运行结果。
注意 :
sh -n $1 2>/tmp/sh.err #将错误的输出到/tmp/sh.err
if [ $? -ne 0 ] #$?不等于0,说明有语法错误。
40、题目要求 : 格式化数字
输入一串随机数字,然后按千分位输出。 比如输入数字串为“123456789”,输出为123,456,789。
参考答案
#!/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=$[$n-1]
done |sed 's/^,//'
echo
实例 :
sed实现数字之间的自动空一格
脚本正确执行的结果
注意 :
n=`echo $1|wc -L` #n表示计算数字的长度,$1是数字串。
for d in `echo $1|sed 's/./& /g'` #sed实现数字的自动空一格,&代表前面的点。
n2=$[$n%3] #$[$n%3] 表示$n除以3,然后添加逗号间隔。
if [ $n2 -eq 0 ] #0表示$n2能够被3整除
echo -n ",$d" #能被3整除的,添加逗号间隔。
echo -n "$d" #不能被3整除的,不添加逗号间隔。
来源 :https://github.com/aminglinux/shell100/blob/master/13.md