shell脚本教程
1 什么是shell脚本
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
1.1 开发环境
Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
Linux 的 Shell 种类众多,常见的有:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
- ……
1.2 初步体验
程序开发一般都是以一个hello world 开始,这里我们也不免俗,新建一个test.sh的文件,写入内容如下:
#!/bin/bash
echo "Hello World !"
#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。echo 命令用于向窗口输出文本。
在linux上运行shell脚本,需要先将脚本文件更改为可执行。然后执行。
chmod +x ./test.sh #使脚本具有执行权限
./test.sh #执行脚本
1.3 语言学习的流程
语言学习的流程我这边总结了比较通用的步骤,这里一定存在一定的狭隘的看法,仅供参考。步骤如下:
1,变量的定义、语法、使用
2,运算符
3,流程控制(条件语句、循环语句)
4,函数的定义和使用
5,...
2 shell脚本基础语法
2.1 变量
# 什么是变量?
变量的概念基本上和初中代数的方程变量是一致的,只是在计算机程序中,变量不仅可以是数字,还可以是任意数据类型.
shell脚本中的变量一般只有两种:数字和字符串。
# 变量的定义
变量的定义有两种方式,直接赋值或者语句赋值。
a,直接赋值
my_name="zhangsan" # 定义了一个值为zcw的变量,变量的名为my_name
my_age=30 # 定义了值为30的变量,变量名为my_age
需要注意:
1、命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
2、中间不能有空格,可以使用下划线(_)
3、不能使用bash里的关键字
4、变量赋值语句等号两侧不能有空格,这点和其他开发语言不一样
b,语句赋值
dir_list=`ls` # dir_list的值即为当前文件下全部文件和文件夹名称
需要注意:
1、ls为linux命令列出当前文件下全部文件和文件夹
2、这种linux命令需要使用(`)包括
# 变量的使用
shell脚本变量的使用和其他语言不同,如java、php、python、c、c++等都是直接引用变量名即可,shell脚本中是需要在变量名前加上($)符号的。
my_name="zhangsan"
echo $my_name
echo ${my_name}
推荐使用第二种方式,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况
echo "my name is $my_namei am ok!"
# 字符串
字符串的可以用单引号,也可以用双引号,也可以不用引号。一般不推荐不用引号。
这里主要说下单引号和双引号的区别。
a,单引号
1、单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
2、单引号必须成对出现
b,双引号
1、双引号可用有变量
2、双引号可用出现转义字符
示例
your_name="runoob"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2 $greeting_3
hello, runoob ! hello, runoob !
hello, runoob ! hello, ${your_name} !
字符串两个方法:
1、获取字符串长度
string="abcd"
echo ${#string} #输出 4
2、提取字符串
string="runoob is a great site"
echo ${string:1:4} # 输出 unoo
# 数组
bash支持一维数组、类似于 C 语言,数组元素的下标由 0 开始编号。
array_name=(value0 value1 value2 value3) #这是一个定义的数组
读取数组
${array_name[n]} # n这里为实际的数字,范围为0——数组长度-1
2.2 运算符
shell运算符主要包括:
- 算数运算符
- 关系运算符
- 布尔运算符
- 字符串运算符
- 文件测试运算符
这里我简单讲解下算数运算、关系运算和逻辑运算。
据名知意,算数就是计算,关系是进行比较的,逻辑就是与或非。
# 算数运算
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。如:
val=`expr 2 + 2` # 前面讲过(`)是执行的linux命令
echo "两数之和为 : $val"
# 关系运算
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
注:
1、需要使用[]包括
2、也可使用test 替换掉[]
2.3 流程控制
主要是控制程序的执行,程序运行一般都是按照顺序执行的,不过也有特殊的,如其他语言中的异步、回调等,不过在shell中一般只考虑顺序执行即可。顺序执行时我们可用通过条件语句来控制程序等运行。
条件语句这里主要介绍下三种常见的:if语句、for循环、case...esac
# if语句
a=10
b=20
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
# for语句
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
for file in `ls`
do
echo file
done
# case...esac语句
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac
2.4 函数
一次定义多处使用。
funWithReturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"
3 ()、(())、[]、[[]]、{}的作用和区别
$()和 ` `
在 bash shell 中,$( ) 与` ` (反引号) 都可用做命令替换用。
例如
version=$(uname -r)和version=`uname -r`都可以是version得到内核的版本号
各自的优缺点:
1、` ` 基本上可用在全部的 unix shell 中使用,若写成 shell script ,其移植性比较高,但反单引号容易打错或看错。
2、$()并不是所有shell都支持。
${ }
${ }用于变量替换。一般情况下,$var 与${var} 并没有什么不一样,但是用 ${ } 会比较精确的界定变量名称的范围。
$[] $(())
$[]和$(())是一样的,都是进行数学运算的。支持+ - * / %(“加、减、乘、除、取模”)。但是注意,bash只能作整数运算,对于浮点数是当作字符串处理的。
[ ]
为test命令的另一种形式,但要注意:
1.必须在左括号的右侧和右括号的左侧各加一个空格,否则会报错。
2.test命令使用标准的数学比较符号来表示字符串的比较,而用文本符号来表示数值的比较。
3.大于符号或小于符号必须要转义,否则会被理解成重定向。
(( ))及[[ ]]
分别是[ ]的针对数学比较表达式和字符串表达式的加强版。
[[ ]]中增加模式匹配特效。
(( ))不需要再将表达式里面的大小于符号转义。
4 实际案例
# 案例1,关闭javaweb程序
#!/bin/bash
name=$(lsof -i:80|tail -1|awk '"$1"!=""{print $2}')
if [ -z $name ]
then
echo "No process can be used to killed!"
exit 0
fi
id=$(lsof -i:8080|tail -1|awk '"$1"!=""{print $2}')
kill -9 $id
echo "Process name=$name($id) kill!"
exit 0
# 案例2,云平台一键配置
#!/bin/bash
# 此脚本用于一键web环境及项目配置
# ver1.0
www="/home/wwwroot/default"
commands=(all ip lnmp web)
lnmpSetFun(){
echo "修改lnmp配置信息"
# php修改
sed -i 's|proc_open,||' /usr/local/php/etc/php.ini && is_php=1 || is_php=0
if test $is_php -eq 0
then
echo "lnmp尚未安装,lnmp配置失败!"
exit
fi
sed -i 's|proc_get_status,||' /usr/local/php/etc/php.ini
sed -i '/PHP_ADMIN_VALUE/d' /usr/local/nginx/conf/fastcgi.conf
service php-fpm restart
# nginx修改
sed -i '/$query_string/d' /usr/local/nginx/conf/nginx.conf
sed -i '/include enable/a\ location / {try_files $uri $uri/ /index.php?$query_string;}' /usr/local/nginx/conf/nginx.conf
sed -i '/root/d' /usr/local/nginx/conf/nginx.conf
sed -i '/index index/a\ root '"$www"'/public;' /usr/local/nginx/conf/nginx.conf
service nginx restart
echo "lnmp配置完成!"
}
webSetFun(){
chmod -R 777 $www/storage && is_web=1 || is_web=0
if test $is_web -eq 0
then
echo "注意!网站未放入或网站路径!网站配置失败!"
exit
fi
chmod -R 777 $www/public
cp /home/wwwroot/default/back.php $www/.env
echo "网站配置完成!"
}
webIpFun(){
read -p "请输入本机IP: " ip
api_ip="http://${ip}"
if [ -z $ip ]
then
echo "尚未输入IP,IP配置失败!"
exit
else
sed -i '/baseUrl/d' $www/public/js/config.js
sed -i '/commandUrl/d' $www/public/js/config.js
sed -i '/^PLATFROM_CONFIG.title/i\PLATFROM_CONFIG.baseUrl = \"'"$api_ip"'\"' $www/public/js/config.js
sed -i '/^PLATFROM_CONFIG.title/i\PLATFROM_CONFIG.commandUrl = \"'"$ip"'\"' $www/public/js/config.js
sed -i '/APP_URL/d' $www/.env
sed -i '/SERVER_URL/d' $www/.env
sed -i '/^ADMIN_HTTPS/i\APP_URL='"$api_ip"'' $www/.env
sed -i '/^ADMIN_HTTPS/i\SERVER_URL='"$api_ip"':8080/energy_command/' $www/.env
echo "IP配置完成!"
fi
}
case $1 in
${commands[0]})
lnmpSetFun
webSetFun
webIpFun
;;
${commands[1]})
webIpFun
;;
${commands[2]})
lnmpSetFun
;;
${commands[3]})
webSetFun
;;
*)
echo "输入指令不正确!"
echo "正确格式为 \"./webset.sh cmd\""
echo "其中cmd包含有all、ip、lnmp、web"
echo "all为一键配置全部,按照说明书正常步骤执行完即可操作"
echo "ip单配置后台及前台ip地址"
echo "lnmp单配置lnmp服务"
echo "web单配置web服务"
;;
esac
echo "配置完成,浏览器输入\"http://本机ip\"访问项目"
# 案例3,云平台项目部署
#!/bin/bash
# 此脚本用于一键部署web项目
# ver1.0
wwwPlat="/home/wwwroot/default"
wwwServer="/home/wwwroot/server"
platMoveFun(){
if [ -e $wwwPlat ]
then
echo "~~~~"
else
`mkdir -p ${wwwPlat}`
fi
`tar -xzvf ./energy_cloud_platform.tar.gz -C ${wwwPlat}`
}
serverMoveFun(){
if [ -e $wwwServer ]
then
`rm -rf ${wwwServer}/*`
else
`mkdir -p ${wwwServer}`
fi
`\cp ./energy_cloud/* ${wwwServer}`
}
echo "###一键部署web文件###"
serverMoveFun
platMoveFun
echo "部署完成!"
5 结语
我这里只是带着简单过了下shell脚本的一些常用语法,实际学习还需要进一步去看文档。
shell语言其实只是简单的基本操作语言,要让其发挥作用还需要深入学习下linux命令,课程中大家应该也看到了,其实很多地方都需要用到linux的命令获取到数据给我们的变量中让我们在进一步处理。
我对于shell的理解是,其实它就是对linux命令提供了更方便的操作和处理方式。
这里我在列下自己目前常用的linux命令。https://www.jianshu.com/p/7f68c0945f2f