07 Shell echo/printf 命令
1. Shell 显示命令
1.1 Shell 显示命令
与其他语言一样,Shell 也有字符串的输出及格式化字符的需求,在本章节我们着重讲解 Shell 中的 echo 与 printf 命令,灵活运用这两个命令,基本上就能满足我们在 Shell 编写中的大多数显示输出及格式化字符串的需求。
1.2 为什么要用显示命令
在我们编写 Shell 脚本的时候需要为用户提供信息提示以及交互式显示,也存在需要记录脚本的执行日志等,此时都需要我们来根据不同的场景,利用 Shell 的显示命令也称输出命令来满足我们的需求。
2. Shell 显示 echo 命令操作
我们明确了 Shell 显示命令的含义及作用,首选让我们来看 echo 命令及基本操作。
2.1 echo 语法
echo 命令语法非常简单:echo [option] [arguments]
,其中根据 option
的不同,赋予了 echo 很多强大的功能。
2.2 echo 常用操作
2.2.1 打印普通字符串
通常默认不带参数就是处理打印普通字符串,例如:
[root@master ~]# echo "hello shell"
hello shell
2.2.2 不换行输出
默认 echo 输出普通字符串为自动换行的,如果不想输出自动换行,可以添加选项 -n
,例如:
[root@master ~]# echo -n "hello shell"
hello shell[root@master ~]#
我们可以看到此时输出就不自动换行,该需求可以在我们写文件的时候使用。
2.2.3 输出变量
在我们前面讲解变量的时候,有提到过在引用变量的时候可以利用 echo
命令,但是此时需要我们注意单引号与双引号的区别。
- 单引号
单引号为将变量名原样输出,不引用其的值,例如:
[root@master ~]# STR1="hello shell"
[root@master ~]# echo '${STR1}'
${STR1}
- 双引号
双引号为引用变量的值进行输出,例如:
[root@master ~]# echo "${STR1}"
hello shell
[root@master ~]# echo ${STR1}
hello shell
我们可以发现在终端如果不显式书写引号,默认就为双引号,也就是引用我们变量的值,但是我们在编写 Shell 脚本的时候尽可能地显示写上引号,这样可以避免不必要的异常发生。
2.2.4 -e 转义
echo
命令使用 -e
选项可以开启转义,处理特殊字符。
n
: 换行符号
[root@master ~]# echo -e "hellonshell"
hello
shell
t
: 制表符,也就是按我们的 tab 键
[root@master ~]# echo -e "hellotshell"
hello shell
r
: 回车键,RETURN
[root@master ~]# echo -e "hellor"
hello
a
: 从系统喇叭送出铃声,ALERT
[root@master ~]# echo -e "a"
\
:显示反斜线本身
[root@master ~]# echo -e "hello \ shell"
hello shell
f
:FORMFEED,换页字符
[root@master ~]# echo -e "hellofshell"
hello
shell
E
:ESCAPE,跳脱键
[root@master ~]# echo -e "hello Eshell"
hello hell
2.2.5 文件操作
- 创建文件
可以利用 echo 命令来创建文件,例如:
[root@master ~]# ls test.sh
ls: cannot access test.sh: No such file or directory
[root@master ~]# echo "hello shell" >test.sh
[root@master ~]# cat test.sh
hello shell
[root@master ~]#
如果需要在一个文件中写入简单内容,不用创建文件然后打开,可以直接利用 echo 命令将内容输入到文件中,文件会自动创建。
- 清空文件
可以利用 echo 来清空文件内容,例如:
[root@master ~]# cat test.sh
hello shell
[root@master ~]# echo >test.sh
[root@master ~]# cat test.sh
2.2.6 感叹号
在 echo 中,如果使用双引号其中带有 !
则会抛出异常,这是因为默认 Shell 开启了感叹号引用内存中的历史命令,可以利用 set +H
进行关闭,如果不关闭该设置还想使用感叹号,可以使用单引号。
[root@master ~]# echo "hello !"
-bash: !": event not found
[root@master ~]# echo 'hello !'
hello !
2.2.7 颜色输出
在 Shell 中我们有时候需要与用户进行交互式操作,如果输出的内容有颜色,对于用户识别更为明显。Shell 中 echo 可以对字体颜色 / 背景 / 显示方式进行控制,如下表:
字体颜色 | 字体背景颜色 | 显示方式 |
---|---|---|
30:黑 | 40:黑 | |
31:红 | 41:深红 | 0:终端默认设置 |
32:绿 | 42:绿 | 1:高亮显示 |
33:黄 | 43:黄色 | 4:下划线 |
34:蓝色 | 44:蓝色 | 5:闪烁 |
35:紫色 | 45:紫色 | 7:反白显示 |
36:深绿 | 46:深绿 | 8:隐藏 |
37:白色 | 47:白色 | |
格式: | ||
33[1;31;40m | # 1 是显示方式,可选。31 是字体颜色。40m 是字体背景颜色。 | |
33[0m | # 恢复终端默认颜色,即取消颜色设置。 |
- 显示方式
for i in {1..8};do echo -e "33[$i;31;40m hello shell 33[0m";done
- 字体颜色
for i in {30..37};do echo -e "33[$i;40m hello shell 33[0m";done
- 背景颜色
for i in {40..47};do echo -e "33[47;${i}m hello shell 33[0m";done
3. Shell 中 printf 命令操作
我们学习了 echo 命令,它通常用于处理常规的需求,还有一些更高级的需求,例如我们希望输出内容指定字符的宽度,左右对齐,格式小数输出等,此场景下需要利用 printf
命令进行处理。
3.1 printf 语法
printf 功能为格式化打印数据,语法为:printf format-string [arguments]
。
- format-string: 为格式控制字符串;
- arguments: 为参数列表。
3.2 printf 注意点
其引用 C 语言中的 printf
命令,但 也有一些区别,需要注意:
- printf 默认情况下末尾不加换行符号,所以如果需要换行,需要显示手动添加
n
; - printf 为格式化输出不对内容做改变操作,尤其在浮点数输出的时候,对其结果不进行改变,这是现实结果有差异;
- 在 printf 中 arguments 为参数列表,例如字符串或者变量,建议个数与 format-string 要求的数量相同;
- printf 不用加括号,arguments 使用空格分隔,不用逗号。
3.3 printf 常用操作
3.3.1 打印普通字符串
[root@master ~]# printf "hello shell"
hello shell[root@master ~]# printf "hello shelln"
hello shell
如果需要换行,需要手动显式添加 n
。
3.3.2 格式字符串
在掌握 printf 前需要先了解 format-string
,其对应着不同的含义,在此我们介绍最常用的格式字符串。
%s
字符串格式化,其中 %s
就是引用后面的字符 shell
[root@master ~]# printf "hello %sn" shell
hello shell
%d
十进制整数
[root@master ~]# printf "age: %dn" 20
age: 20
- 左对齐
printf 可以使得左对齐,例如 %-10s
指一个宽度为 10 个字符,左对齐利用 -
表示,任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
[root@master ~]# printf "hello %-10s%sn" shell 。
hello shell 。
- 右边对齐
右对齐利用 +
表示,%+10.2f
指格式化为小数,其中 10 表示 4 个字符宽度,.2 指保留 2 位小数。
[root@master ~]# printf "hello %+10s%sn" shell 。
hello shell。
[root@master ~]# printf "hello %+10.2f %sn" 3.1415 。
hello +3.14 。
- 其他
当然一些其他格式化字符,在此举例最常用的,其他的可参考如下:
%c ASCII字符.显示相对应参数的第一个字符
%d,%i 十进制整数(常用)
%e 浮点格式([-d].precisione [+-dd])
%E 浮点格式([-d].precisionE [+-dd])
%g %e或%f转换,看哪一个较短,则删除结尾的零
%G %E或%f转换,看哪一个较短,则删除结尾的零
%s 字符串(常用)
%u 不带正负号的十进制值
%x 不带正负号的十六进制.使用a至f表示10至15
%% 字面意义的%
%X 不带正负号的十六进制.使用A至F表示10至15
3.3.3 其他
- 单双引号
在 printf 中,单双引号都一致。
[root@master ~]# printf "hello %sn" shell
hello shell
[root@master ~]# printf 'hello %sn' shell
hello shell
- 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用进行多行输出
[root@master ~]# printf 'hello %sn' shell python go
hello shell
hello python
hello go
[root@master ~]# printf "%s %s %s %sn" a b c d e f g h i j
a b c d
e f g h
i j
- 如果没有 arguments,那么则对应使用默认值表示, % s 用 NULL 代替,% d 用 0 代替
[root@master ~]# printf "%s default %d n"
default 0
3.3.4 printf 转义
printf 的转义与 echo 中的一致,可参考 echo 中的转义。
4. 实例
4.1 需求
例如给出如下 nginx 的访问日志,需要对其进行分析并且输出不同的状态码,利用颜色不同进行区分不同的状态码。
112.65.61.117 - - [05/Nov/2019:17:10:54 +0800] "GET /js/chunk-2eca3a5a.2f1d5ea3.js HTTP/1.1" 200 5276 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1278.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat" "-"
112.65.61.117 - - [05/Nov/2019:17:10:54 +0800] "GET /js/chunk-91d36e6e.a1444c20.js HTTP/1.1" 200 12674 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1278.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat" "-"
112.65.61.117 - - [05/Nov/2019:17:10:54 +0800] "GET /js/chunk-vendors.3a6c246c.js HTTP/1.1" 404 260490 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1278.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) Apessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:54 +0800] "GET /js/app.ec4e6290.js HTTP/1.1" 200 11149 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:55 +0800] "GET /js/chunk-vendors.3a6c246c.js HTTP/1.1" 200 260482 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:55 +0800] "GET /api/2 HTTP/1.1" 500 502 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:55 +0800] "GET /js/chunk-2eca3a5a.2f1d5ea3.js HTTP/1.1" 200 5276 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:55 +0800] "GET /css/chunk-91d36e6e.a5cb4df4.css HTTP/1.1" 200 1133 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:55 +0800] "GET /js/chunk-03341f87.78501520.js HTTP/1.1" 200 1059 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:55 +0800] "GET /js/chunk-91d36e6e.a1444c20.js HTTP/1.1" 200 12674 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:56 +0800] "GET /api/1 HTTP/1.1" 500 39193 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:56 +0800] "GET /img/download.f4b65200.png HTTP/1.1" 200 7737 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:57 +0800] "GET /img/background.fc2d80f1.png HTTP/1.1" 200 57711 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:57 +0800] "GET /img/peitu.a89ef99f.svg HTTP/1.1" 301 106569 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
223.104.189.205 - - [05/Nov/2019:17:10:57 +0800] "GET /fonts/element-icons.535877f5.woff HTTP/1.1" 200 28200 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.5(0x17000523) NetType/4G Language/zh_CN" "-"
112.65.61.117 - - [05/Nov/2019:17:10:59 +0800] "GET /img/download.f4b65200.png HTTP/1.1" 200 7737 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1278.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat" "-"
112.65.61.117 - - [05/Nov/2019:17:10:59 +0800] "GET /img/scan.d3d981fc.png HTTP/1.1" 404 39193 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1278.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat" "-"
112.65.61.117 - - [05/Nov/2019:17:10:59 +0800] "GET /img/background.fc2d80f1.png HTTP/1.1" 200 57711 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1278.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat" "-"
112.65.61.117 - - [05/Nov/2019:17:11:00 +0800] "GET /img/peitu.a89ef99f.svg HTTP/1.1" 200 106569 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1278.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat" "-"
14.106.162.188 - - [05/Nov/2019:17:14:40 +0800] "GET /index HTTP/1.1" 200 535 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.8(0x17000820) NetType/4G Language/zh_CN" "-"
14.106.162.188 - - [05/Nov/2019:17:14:40 +0800] "GET /css/app.7d918353.css HTTP/1.1" 200 1290 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.8(0x17000820) NetType/4G Language/zh_CN" "-"
14.106.162.188 - - [05/Nov/2019:17:14:40 +0800] "GET /js/app.ec4e6290.js HTTP/1.1" 404 11149 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.8(0x17000820) NetType/4G Language/zh_CN" "-"
4.2 思路
可以利用上节课的数组进行状态存储,之后利用统计每个状态的数量来利用 echo 颜色进行区分显示。
4.3 实现
- 将 nginx 访问日志文件存储为 nginx.log,可以利用 cat 命令来创建文件
cat > nginx.log <<EOF
112.65.61.117 - - [05/Nov/2019:17:10:54 +0800] "GET /js/chunk-2eca3a5a.2f1d5ea3.js HTTP/1.1" 200 5276 "https://smartsds.tools.anchnet.com/index" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1278.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat" "-"
...
EOF
- 编写代码,其中为们利用 cut 对 nginx 日志文件进行分割,状态码的列尾第九列
#!/bin/bash
# Description: nginx status
# Auth: kaliarch
# Email: kaliarch@163.com
# function: nginx status check
# Date: 2020-03-21 14:00
# Version: 1.0
# 对输入的nginx日志文件进行判断
NGINX_LOG=$1
# 定义管理数组
declare -A HTTP_STATUS
# 对数组进行内容赋值
# 利用netstat命令来过滤出关系的一列数据
for status in $(cat ${NGINX_LOG} |cut -d" " -f9)
do
# 对状态相同状态的HTTP进行数值累加
let HTTP_STATUS[${status}]++
done
# 将统计完成的TCP链接状态及数据记录到日志中
for i in ${!HTTP_STATUS[@]}
do
if [ ${i} -eq 404 ];then
echo -e "33[34;40m文件${NGINX_LOG}中状态码为${i}的数量为${HTTP_STATUS[${i}]} 33[0m"
elif [ ${i} -eq 500 ];then
echo -e "33[31;40m文件${NGINX_LOG}中状态码为${i}的数量为${HTTP_STATUS[${i}]} 33[0m"
elif [ ${i} -eq 200 ];then
echo -e "33[32;40m文件${NGINX_LOG}中状态码为${i}的数量为${HTTP_STATUS[${i}]} 33[0m"
else
echo -e "33[36;40m文件${NGINX_LOG}中状态码为${i}的数量为${HTTP_STATUS[${i}]} 33[0m"
fi
done
- 执行结果
[root@master shell_echo]# bash nginx_status.sh nginx.log
文件nginx.log中状态码为200的数量为17
文件nginx.log中状态码为301的数量为1
文件nginx.log中状态码为404的数量为2
文件nginx.log中状态码为500的数量为2
5. 注意事项
- 在 echo 变量引用时,我们推荐勤用引号,单引号为原样输出字符串,双引号为输出变量的值;
- printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植更好,如果后期考虑平台移植问题,建议使用
printf
。
6. 小结
在 shell 中我们可以利用 echo 来记录程序的日志,或对文件进行新增内容输入,或利用其进行颜色打印,可以输出带有颜色的漂亮提示。在设计多平台移植性问题的时候,为们可以优先考虑 printf
,对于数组显可以使用 printf
来完成,灵活运用显示使得脚本编写更为方便灵活。