工作中shell脚本的实用频率非常高,比如作为不同语言之间的胶水,或者是为了避免重复劳动而写的一次性工具。熟练掌握shell脚本的一些使用技巧,绝对是提高工作效率的利器!PS.本文中指的Shell都是Bash
shell的启动方式通过两种维度来划分,交互与非交互,登录与非登录。这里面其实比较复杂,不同的发行版本可能也不太一样,都可以另外写一篇来谈了。简单的说一般情况下你login了一台机器,在bash下就是交互登录启动,这个时候shell会先source /etc/profile,~/.bash_profile, ~/.bash_login, ~/.profile这3个文件(如果有的话),然后一般~/.bash_profile里面会source一把~/.bashrc。所以这个时候你执行一些脚本的话环境变量已经配置好了。但是如果是用crontab启动,就是非交互启动,这个时候shell只会source一边/etc/profile, 那么很多环境变量是没有设置的,所以通过crontab启动的脚本在开头最好都source一下~/.bash_profile或者~/.bashrc
---------------------------------------我是分割线------------------------------------
场景1
job1每天会执行一次,完成后会输出一个done文件到目录/home/minecraft/daily/yyyymmdd下,然后job1完成后执行job2
对于这个场景,我们可以每天在固定时间起一个crontab任务,任务执行一个shell脚本,该脚本每隔固定的时间去探查done文件是否存在,如存在则执行job2. 为了防止这个任务一直等待下去,一般会添加一个探查的次数限制。
另外一种思路是每天用crontab间隔一段时间就起一次任务来探查done文件,如存在则执行job2.这个思路存在一个问题,当我前一次探查到done后开始执行job2,后一次还是会来继续探查done文件,重复启动job2,产生错误。可以通过设置一个lock文件来终止后面的所有探查进程来保证job2的唯一性。在当前场景下思路1比较简洁有效。
思路1代码如下
1 DATE=$(date +%Y%m%d) 2 retry=60 3 while :; 4 do 5 if [[ -e /home/minecraft/daily/${DATE}/done ]]; then 6 break 7 else 8 ((retry--)) 9 sleep 10m 10 fi 11 if [[ ${retry} -le 0 ]]; then 12 exit 1 13 fi 14 done 15 16 run job2 17 18 exit 0
假如job1不是touch一个done文件,而是输出一个文件,那么我们就需要判断2点:1.文件是否存在;2.文件是否已经完成写入。第一点好判断,第二点的话可以每隔一段时间check一下文件大小,当2次check的大小不变,就可以认为文件已经写入完成了。查看文件大小可以用
1 size=$(wc -c < file)
或者利用管道
1 size=$(cat file | wc -c)
又假设job1写入的是1天前的数据,那么可以利用
1 NDAYAGO=$(date "1 ady ago" "+%Y%m%d")
来获得日期字符串
TO BE CONTINUE...