Shell脚本的书写
最近的一个项目中,一直在追查Kafka读取数据的问题。在monitor工具中会列出每个partition的消费者的IP,另一方面每台机器消费了多少数据能拿到的只有host name。如何从这些ip映射到host name,并分析每个机器所处的cluster有多少台机器,消费多少个partition做一些简单分析的自动化脚本。因此又重新倒腾了下shell脚本。
对shell脚本不熟悉的同学看来,shell只是一系列的命令,但是只有真正熟悉之后,才能了解到它的强大,尤其是对文本\文件的各种便利化处理,以及它天生更linux系统结合的特性,使它成为一种高效的脚本利器。
本篇文章回顾了写好shell脚本需要了解的几个基本元素,几乎每个脚本都需要用到的一些基本知识。
1. Usage函数
Usage函数描述一个shell脚本的用途,描述可以使用的参数,以及给出一些简单的运行命令样本。
function usage() {
echo "$0 [-a]"
echo "Usage: "
echo -e "\t Get dns name for each host from IP"
echo -e "\t -a Analysis the count of hosts for each cluster"
echo -e "\t -h Print help message"
echo -e "Sample: $0 Running command without any argument will check host name for each ip and print in console"
echo -e "Sample: $0 -a Running command to further analysis the hosts number for each cluster"
}
说明:
- $0的作用是显示当前的脚本路径名字
- echo -e中-e的作用是为了输出制表符,如果没有-e会直接输出"\t"
2. 脚本的参数传递
虽然shell脚本提供了简单的数字偏移来获取每个参数, 如$1用来获取第一个参数,但是如果有多个参数,这样传递就不够清晰,容易产生传递错误(尤其当有个参数为空的时候,会把下一个参数当成当前参数)。因此一个好的参数传递,推荐使用getopts。
while getopts ":ah" opt
do
case ${opt} in
a)
analysis
;;
h)
usage
;;
?)
usage
esac
done
说明:
- getopts里面的参数分为两种,一种无需带参数,如本例中的h和a,都是不需要参数的。如果需要传入参数,比如-n Devin, 需要传入参数的话,在参数n后面加“:", 比如":n:ah".
- ?表示没有匹配到的参数。
- 开头“:",表示会屏蔽掉需要传参数的没有传参数的错误。
3. 字符串的处理
shell里面所有数据的基本形式,都是字符串,因此懂得字符串常用的处理方式对于shell脚本来说至关重要。
3.1 获取最后一个字符
对于字符串的截取,shell提供了一套非常方便方式,以取值"{}"来获取。
function get_last_char() {
name=$1
echo ${name: -1}
}
说明:
- name是一个字符串变量名,-1表示截取最后一个字符。更一般的写法是${var:0:5},表示从左边第一个字符开始,截取5个字符长度。如果一直到最后,可以省略“:5"。 如果从右边起则在表示位置的数字前加“0-”,如${var:0-15:10}表示从右边倒数第15个字符开始截取10个字符。
3.2 字符串的替换
sed是字符串处理的利器,可以用它来进行文本替换非常方便。
echo "https://wudevin.cn." | sed 's/.$//g'
说明:
- 上述命令的作用是去掉文本中最后一个“."(位于cn后)。
- ".$"中$的作用表示行末。g表示全局替换。
更多sed命令的用法,参照:https://www.runoob.com/linux/linux-comm-sed.html
3.3 字符串分割
awk是最常用的场景是用来获取其他命令输出结果的某一些字段。一般文本的组织都有一定的格式,如csv是以“,"作为文本的分割符。如果从这些以一定分隔符分割开来的文本中,获取想要的字段呢?这就是这个命令的用武之地。
echo "Wu Devin" | awk -F\ '{print $NF}'
说明:
- 上述命令的输出为:Devin。awk的-F参数是用来指定分隔符,这里指定分隔符是空格。但是空格是特殊字符,所以用了转义字符""。
- print里面的作用是选取你想要的column。 NF表示最后一个column。当然你也可以用数字, 1表示第一个column,2表示第2个column,以此类推。0表示整个文本。
4. 流程控制
4.1 条件表达式
条件表达式,也就是最基本的表达式if。
if [ -z "$var" ]
then
echo "\$var is empty"
else
echo "\$var is NOT empty"
fi
说明:
- 上述表达式的作用是判断字符串是否为空,然后走不同的分支。
4.2 循环迭代表达式
最常见的方式,为在一个数组中迭代。
clusters=("d12" "d13" "d14" "c1" "c2")
for cluster_name in "${clusters[@]}" ; do
if [[ ${cluster_name} == c* ]]; then
analysis_c_cluster ${cluster_name}
else
analysis_d_cluster ${cluster_name}
fi
done
5. 文件处理
5.1 写入文件
往文件里面以覆盖的方式写入数据
echo "something write to file" > fileName.txt
往文件里面以追加的方式写入数据
echo "something write to file" >> fileName.txt
5.2 从文件读取数据
可以跟for表达式结合起来,每次读取处理一行数据。
for host in `cat host.txt` ; do
echo "line: ${host})"
done
标题:Shell脚本的书写
作者:wuhaifengdhu
地址:https://wudevin.cn/articles/2019/12/01/1575210308906.html
只有站在峰顶的人,才能看见星辰大海。