你问我Shell脚本怎么写?
网上一搜一大把“标准答案”。
但那些都太干净了,干净得像没活过。
真正的脚本,是在报错和改错里滚出来的。
今儿个咱不弄那些不实的,亲手撸四十多个片段,从变量开始一直撸到自动化部署,情况就如同被狗啃过那般,然而每一个字都携带着服务器的热度。
一、变量,不过是给数据起了个名儿
姓名=“张三”
年龄=25
echo “${姓名} 今年 ${年龄} 岁”
就这么简单。
但,等号两边,千万,别加空格,Shell,这玩意儿,神经质,加了,就炸。
第一次写脚本的人,十个有八个死在这上面。
随后知晓,变量存有两类,其一为本地变量,一旦关闭终端便失却记忆,其二是环境变量,子子孙孙都能够继承。
export一把,就能传宗接代。
二、只读和删除,像极了前任
readonly 姓名
unset 年龄
只读这东西,设了就改不了,一改就报错。
像不像那些说死不改的决定?
unset更绝,直接抹掉存在,再引用就是空空如也。
有一回,针对生产环境所编写的脚本,我竟然没有添加只读属性,结果呢,被他人一不小心手滑给改动了配置,以至于数据库无法正常连接了。
从那以后,关键变量全readonly。
三、if判断,脚本的良心
if [ -e “$1” ]; then
echo “文件在呢”
else
echo “没了,真没了”
fi
中括号两边必须有空格,这是Shell的仪式感。
对一个参数予以接收,对文件是否存在展开判断,如此也就仅仅这么几行,然而每天都能将我从无尽困境中解救许许多多次数。
e是文件存在,-f是常规文件,-d是目录。
记不住没关系,我也是现查。
四、case分支,菜单的灵魂
echo “1. 看日期 2. 算和 3. 滚蛋”
read opt
case $opt in
1) date ;;
2) echo $((2+3)) ;;
3) exit ;;
) echo “选啥呢兄弟” ;;
esac
case比if清爽多了,尤其是选项多的时候。
那个成双成对的分号就是起到强制终止的作用,要是忘记写了就会毫无阻碍地一直不断往下进展,曾经多次让遭受蒙蔽或陷害吃了亏。
五、综合:给文件数数
read -p “文件名:” f
if [ -f “$f” ]; then
wc -l “$f”
else
echo “没这文件,逗我玩呢?”
fi
用户输入→判断存在→数行数。
简单三步,但这就是脚本的日常——接收输入,做判断,给结果。
六、while循环,倒数的浪漫
read -p “从几开始倒数:” n
while [ $n -gt 0 ]
do
echo $n
((n--))
done
echo “时间到!”
gt是大于,-lt是小于。
记得让n递减,不然变死循环,终端能给你输出到地老天荒。
七、函数,代码的抽屉
function 求积 {
local a=$1
local b=$2
echo $((ab))
}
result=$(求积 5 6)
echo “积是 $result”
函数需要先进行定义,而后才能够调用,Shell是按照逐行的方式运行的,它与其他语言不同,其他语言是先进行编译的。
关键在于local倘若没有它那变量便会是全局的在函数里对值进行修改外面也会跟着改变这样就乱套了。
八、grep、sed、awk,文本三剑客
grep “关键词” 日志.log
sed ‘s/old/new/g’ 原文件 > 新文件
以冒号为分隔符,{打印第一个字段“→”第六个字段},针对/etc/passwd文件。
grep找行,sed换词,awk切列。
在awk那一行,通过 -F:来做指定的以此冒号作为分割的操作$1所代表的是用户名,$6所代表的则是家目录。
就这么几行,几百个用户的信息一目了然。
九、xargs,批量狂魔
查找,路径为/tmp的目录,文件名是.log的文件,修改时间超出3天的这样的文件们,然后使用xargs命令,删除这些文件,删除时使用强制删除选项|-f|。
find找出三天前的.log,xargs喂给rm。
中间加个|,搞定。
要是没有xargs呢,find自身配套的-delete操作一样能执行的,然而xargs具备更强的灵活性,它可以衔接各类不同的命令。
十、定时任务,深夜的守护者
0 2 /backup.sh
crontab -e 加这行,每天凌晨两点跑备份脚本。
五个星分别是分时日日月周,表示任意。
0 2是两点整, 是每天每月每周几都行。
十一、参数校验,防呆设计
if [ $# -eq 0 ]; then
echo “用法: $0 目录路径” >&2
exit 1
fi
$#是参数个数,$0是脚本名。
没传参就报错退出,>&2把提示扔到错误输出,标准操作。
十二、重定向,日志的分流
将当下的日期打印之后,echo再把打印出的日期,与“开始备份”连接起来,朝着名为run.log的文件append写信息。
>>追加,>覆盖,2>>专门收错误。
分开正常日志与报错,如此一来,在排查问题之际,便无需于一堆输出当中像大海捞针那般寻找。
十三、综合:备份.conf文件
bakdir等于,斜杠backup,斜杠,美元符号date,加号,百分号Y,百分号m,百分号d,右括号。
mkdir -p “$bakdir”
cp .conf “$bakdir”
每天一个目录,按日期命名。
简单,但有效。
找起历史版本来,一眼就知道哪天改的。
十四、set -e,出错就停
#!/bin/bash
set -e
错误的命令
echo “这行不会执行”
set -e一开,脚本遇到错误立马死,不往下走。
调试时特别好用,省得错误蔓延,最后找不着北。
上线脚本我必加这行。
十五、进程管理,杀或不杀
pgrep nginx
pkill nginx
pgrep查进程号,pkill直接送走。
撰编服务开启停止的脚本过程里头,首先凭借着pgrep去检查其在不在,继而后根据情况拿定是对其进行启动还是将其解除。
十六、模块化,代码复用
在 math.sh 里
创建一个名为add的函数,该函数执行这样的动作,即输出由$1与$2相加之结果所产生的内容。
在 main.sh 里
source ./math.sh
result=$(add 3 5)
source(或者.)可以把另一个脚本的内容导进来。
这样公共函数放一个文件,哪哪都能用,不用复制粘贴。
十七、远程执行,隔空取物
借助ssh,让user登录到192.168.1.100,执行“df -h”这样的操作。
前提是配了免密登录。
配好之后,就能在本地写脚本,远程执行命令。
批量操作几十台服务器,就靠这个。
十八、打包压缩,归档的艺术
执行 tar, 参数为 -czf, 目标文件名为 “${dir除去后方斜杠后的部分}_$(date 按照 %Y%m%d 格式输出的结果).tar.gz”, 其中源文件为 “$dir”。
${dir##/}是去掉路径前缀,只保留目录名。
将其进行打包之后,最好再次去做一下验证,运用tar-tzf这个指令,查看一下是否能够把内容给列出来,以此来保证压缩包没有出现损坏的情况。
十九、正则,模式之眼
要是,依据,这样的情况,即,当,这一,“$phone”,符合,正则表达式,^1[0-9]{9}$,之时,那么。
echo “手机号合法”
fi
^开头,$结尾,[0-9]是数字,{9}是九次。
这个模式匹配11位手机号,第一位是1,后面九位数字。
正则学好了,处理文本如虎添翼。
二十、日志规范,有迹可循
log_info这个函数,它所做的事情是,先这么干,那就是,输出这么个内容,具体是这个内容,它是由date加上日期和时间格式所得到的,紧接着中括号里面是INFO,然后是美元符号后面接小于号所关联的内容,最后是分号。
时间戳+级别+信息,这是日志的标配。
单纯光有回声是不行的,必须要使得人能够知晓在何时出现了何种状况,究竟是属于正常的信息范畴之内,还是属于错误相关的情况。
二十一、自动化部署,一键到位
通过yum,进行安装,以-y为参数,安装gcc,还要安装pcre-devel,也要安装zlib-devel。
尝试通过wget工具,去获取nginx.org这个网站上的download目录下的nginx - 1.20.1.tar.gz文件,以进行下载操作。
tar -xzf nginx-.tar.gz
cd nginx-
进行,./configure,设置前缀为,/usr/local/nginx,接着,执行make,然后,执行make install。
从装依赖到编译安装,全自动。
第一次去跑的时候,或许会缺少这缺少那,那就多次去试试,将所有相关依赖通通弥补完善起来,于是就能够一键安装Nginx了。
二十二、服务启停,标准动作
case $1 in
执行) 系统管理工具启动) 网络服务器软件。
stop) systemctl stop nginx ;;
重新启动,具体操作是通过运行“systemctl restart nginx”命令来实现,其中分号是命令相关的特定符号标识。
用systemctl来查看nginx的状态,这种查看就叫做status,即systemctl status nginx。
),显示 “用法: $0 {开始|停止|重启|状态}”。
esac
这是Linux服务的标准接口。
写脚本也这样,用户一看就懂,不用学。
二十三、批量服务器,数组+循环
服务器列表等于,“root@192.168.1.1”,“root@192.168.1.2”,这两个地址放在 “( )” 中。
for s in ${servers[@]}; do
ssh $s “uptime”
done
服务器列表放数组里,循环遍历,ssh上去执行命令。
几十台机器的负载,一分钟全看完。
二十四、数据库备份,保命要紧
采用mysqldump这个工具,以用户名为root,密码为特定字符串的方式,针对数据库名 ,将其内容生成文件,文件路径为 /backup/mysql/ ,文件名为数据库_加上按照日期格式年、月、日组合生成的.sql文件,日期格式通过date命令加上%Y%m%d来获取。
搜索 /backup/mysql 路径下,类型为此为普通文件的文件,修改时间超过7天的,然后执行删除操作。
备份完还得删旧的,不然硬盘迟早爆。
保留最近7天的,是个好习惯。
二十五、权限检查,不干蠢事
if [ “$(id -u)” -ne 0 ]; then
echo “请用sudo执行” >&2
exit 1
fi
id -u返回用户ID,root是0。
若并非root身份就请退离,免得因权限不够致使执行到中途失败,从而留下一连串极为棘手的遗留问题。
二十六、until循环,等到天荒地老
do
sleep 5
done
echo “Nginx起来了”
until和while相反,条件为真时才停。
在此处用以等待Nginx端口启动起来,常常被用于启动脚本的程序当中,以此保证服务确实有效地可以使用之时才往下一步继续行进。
二十七、脚本库,我的兵器谱
工具类: 文本处理、格式转换、批量改名
监控类: 端口检查、负载报警、日志告警
部署类: 一键安装、代码发布、配置同步
撰写下三四十个脚本后,要依据类别妥善放置,还要撰写一份README,不然三个月往后自己也没法看懂。
二十八、每日必做
写完脚本,必须跑一遍。
一定会报错——语法错、权限错、路径错。
没关系,改就是了。
不改到能跑,绝不收工。
二十九、积累库,时间的朋友
把日程按阶段来构建目录,将day01、day02等人每天的脚本妥善存储好。
后来遇到类似需求,直接cp过来改两行,比从头写快多了。
三十、进阶之路
set -x能看到每一行执行的细节,调试神器。
正则进阶能匹配更复杂的模式。
向着更高层次迈进时,能够尝试去模拟awk那种小范围施展功效的做法,亦或是借助Python编写复杂的逻辑内容,随后通过Shell进行调用。
写着写着,就写嗨了。
不知不觉三千多字,远超要求的1200。
Shell这东西,入门容易,精通难。
难度并非存在于语法方面,而是在于思维,具体而言,是如何将手工操作转化为自动化的,是怎样去思考各类意外状况的,是如何使得脚本如同老黄牛那般健壮的。
40多个片段,每个都是实战里摔出来的。
最初是进行极简单的变量去定义,接着要对几十台的服务器开展批量的操作,随后得一键去部署Nginx,各个阶段都存在问题,每一步都脚踏实地。
别指望一次写对。
写脚本的本质,就是不断试错、不断修改的过程。
在虚拟机当中随意地进行各种折腾,一旦出现报错情况便去进行修改,修改完成后再次进行尝试,一直持续到它能够稳定地跑起来为止。
最终你会发觉,最畅快的并非脚本运行成功的那个时刻,面是往后每一次面临同样情形,你都能够从容地讲:“编写个脚本去运行一回。”。

Comments NOTHING