写下这篇文章,是对本身在学习和使用过程当中的总结,文笔不是很好,若是有什么问题欢迎沟通交流php
Github地址:https://github.com/hi-dhl/fast_guidesjava
Shell是指一种应用程序,这个应用程序提供了一个界面,用户经过这个界面访问操做系统内核的服务, Shell脚本(shell script),是一种为Shell编写的脚本程序。咱们常常说的shell一般都是指shell脚本。python
Shell跟java、php、Python编程同样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就能够了。mysql
Mac OS,Linux 自带了shell解释器,Windows比较麻烦,由于Win7专业版和旗舰版默认安装PowerShell,标准版和家庭版中就没有安装的,为了方便建议安装cygwinnginx
PHP、Python是属于高级编程语言,可是也能够作Shell编程,由于只要有解释器,也能够用做脚本编程git
以下是一个Python Shell Script示例(假设文件名叫op_python_base.py):github
#!/usr/bin/env python3 //告诉Python从系统环境中找python
# -*- coding: utf-8 -*- //设置为UTF-8编码
for index in range(10):
print(index);
复制代码
源码:op_python_basesql
以下是一个PHP Shell Script示例(假设文件名叫op_php_base.php):shell
#!/usr/bin/php
<?php
for($i=0 ;$i<10; $i++){
echo $i;
}
?>
复制代码
源码:op_php_baseapache
既然PHP、Python均可以用来写脚本编程,那为何还要学习陌生、晦涩难懂的Shell,主要有一下几个缘由
环境兼容性,Win7专业版和旗舰版默认安装PowerShell,标准版和家庭版中就没有安装的,其余主流的操做系统都预制了Shell解释器,因此使用sh、bash编写,提供给其余人使用是很是方便的,可是PHP、Python 等等须要安装相应的环境
若是你想作一些定时任务好比说检测进程是否存在,自动备份,或者说自动部署环境、服务器之间的数据同步等等sh、bash会是你最好的选择
sh: Bourne shell,POSIX(Portable Operating System Interface)标准的shell解释器,它的二进制文件路径一般是/bin/sh
bash: Bash是Bourne shell的替代品,属GNU Project,二进制文件路径一般是/bin/bash
我相信写过代码的童鞋,应该对下面的代码很熟悉并不陌生,(假设文件名叫op_base.sh):
#!/usr/bin/env bash
mkdir code
cd code
for ((i=0; i<3; i++)); do
touch test_${i}.txt
echo "shell很简单" >> test_${i}.txt
done
复制代码
第一行:从系统path中寻找指定脚本的解释程序 第二行:建立 名叫code文件夹 第三行:进入建立的文件夹 第四行:for循环3次 第四行:建立文件 第五行:往建立的文件中写入信息 第六行:结束循环
mkdir, touch,cd,touch,echo都是系统命令,在命令行下能够直接执行 for, do, done 是shell脚本语言 for循环的语法
源码:op_base.sh
新建一个文件,扩展名为sh(sh表明shell),扩展名并不影响脚本执行,见名知意就好,若是你用php,扩展名为php,若是你用Python,扩展名为python
第一行通常是这样:
#!/usr/bin/php
#!/usr/bin/env python3
#!/usr/bin/env bash 复制代码
#!”是一个约定的标记,它告诉系统这个脚本须要什么解释器来执行 /env 是系统的PATH目录中查找
chmod +x op_base.sh
./op_base.sh
复制代码
第一行设置 op_base.sh可执行权限 第二行执行op_base.sh
/bin/sh op_base.sh
复制代码
定义变量时,变量名前不须要加符号和Python同样可是在PHP语言中变量须要加$,如:
my_name="jack"
my_name='jack';
复制代码
ps: 变量名和等号之间不能有空格,变量后面不能有;
Shell中的引号和PHP相似,字符串能够用单引号,也能够用双引号
单引号字符串的限制:
双引号:
可是在Python中单引号和双引号是没有区别,可是Python 还有三个引号,在三个引号内字符都不会被转义
对于已经定义过的变量,使用的适合在前面添加$
echo $my_name
echo ${my_name}
复制代码
变量名外面的花括号是可选的,加不加都行,建议使用第二种形式
以“#”开头的行就是注释,会被解释器忽略。
sh里没有多行注释,只能每一行加一个#号。就像这样:
#--------------------------------------------
# Author: jack
# weibo: OO是有情怀的PM
#
# Notes: 10分钟入门Shell脚本编程
#
# Project home page:
# https://github.com/dpm100/fast_guides
#--------------------------------------------
复制代码
字符串能够用单引号,也能够用双引号,也能够不用引号。单双引号的区别跟PHP相似
Shell不像其余语言有php、python 有不少数据类型,在Shell中经常使用的数据类型字符串数字和字符串(ps: 除了数字和字符串,也没啥其它类型好用了,哈哈)
单引号字符串的限制:
双引号:
my_name="jack";
my_age="20岁"
echo $my_name $my_age
echo $my_name$my_age
复制代码
echo ${#my_name}
复制代码
echo ${my_name:0:2}
复制代码
源码:op_str.sh
在Shell中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的通常形式为:
name=(name1 name2 name3)
复制代码
还能够单独定义数组的各个份量:
ary[0]=name1
ary[1]=name2
ary[3]=name3
复制代码
ps: 能够不使用连续的下标,并且下标的范围没有限制
读取数组元素值的通常格式是:
${数组名[下标]}
复制代码
例如:
echo ${name[0]}
复制代码
使用@符号能够获取数组中的全部元素,例如:
echo ${name[@]}
复制代码
获取数组长度的方法与获取字符串长度的方法相同,例如:
# 取得数组元素的个数
length=${#name[@]}
echo $length
# 或者
length=${#name[*]}
echo $length
# 取得数组单个元素的长度
lengthn=${#name[n]}
echo $length
复制代码
源码:op_arry.sh
和Java、PHP、Python等语言不同,sh的流程控制不可为空,如(如下为PHP流程控制写法):
<?php
if (isset($_GET["q"])) {
search(q);
}
else {
// 不作任何事情
}
复制代码
在sh/bash里可不能这么写,若是else分支没有语句执行,就不要写这个else
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
复制代码
例子:
#!/usr/bin/env bash
a=1
b=2
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
elif [ $a -lt $b ]
then
echo "a 小于 b"
else
echo "没有符合的条件"
fi
复制代码
源码:op_if.sh
Shell的for循环和Python 有点相似
for index in 1,2,3,4,5:
print(index);
复制代码
for index in 1 2 3 4 5; do
echo "index="$index
done
复制代码
for ((i=0; i<5; i++)); do
echo "i="$i
done
复制代码
源码:op_for.sh
while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令一般为测试条件。
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
复制代码
源码:op_while.sh
sh脚本结合系统命令便有了强大的威力,在字符处理领域,有grep、awk、sed三剑客,grep负责找出特定的行,awk能将行拆分红多个字段,sed则能够实现更新插入删除等写操做。
path=/var/log
log=${path}/httpd-mysql.log
name=(apache mysql)
exs_init[0]="service httpd start"
exs_init[1]="/etc/init.d/mysqld restart"
for ((i=0; i<2; i++)); do
echo "检查${name[i]}进程是否存在"
ps -ef|grep ${name[i]} |grep -v grep
if [ $? -eq 0 ]; then
pid=$(pgrep -f ${name[i]})
echo "`date +"%Y-%m-%d %H:%M:%S"` ${name[$i]} is running with pid $pid" >> ${log}
else
$(${exs_init[i]})
echo "`date +"%Y-%m-%d %H:%M:%S"` ${name[$i]} start success" >> ${log}
fi
done
复制代码
解释:检测 nginx、mysql进程是否存在,若是不存在了会自动从新启动。 脚本每次运行会写日志的,没事能够去看看该日志文件,若是进程是否是真的常常性不存在,恐怕就要排查一下深层缘由了。
crontab -e
复制代码
在文件最后添加一行:
*/5 * * * * /xxx/check_nginx.sh > /dev/null 2>&1
复制代码
上表示每 5 分钟,执行一下脚本 /xxx/check_nginx.sh,其中xxx表明路径
/dev/null 2>&1 的意思是该条shell命令将不会输出任何信息到控制台,也不会有任何信息输出到文件中。
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * command to be executed
复制代码
service crond restart
复制代码