1.shell初步了解
1.1 什么是Shell
Shell是一个命令解释器,它的作用是解释执行用户输入的命令及程序等,用户输入一条命令,Shell就解释执行一条。
这种从键盘一输入命令,就可以立即得到回应的 对话方式,被称之为交互的方式。
Shell存在于操作系统的最外层,负责直接与用户对话, 把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕返回给用户,当我们输入 系统用户名和密码,登录到Linux后的所有操作都是由 Shell解释并执行的。
1.2.什么是Shell脚本
当命令或程 序语句不在命令行下执行,而是通过一个程序文件执行 时,该程序就被称为Shell脚本。
如果在Shell脚本里内置了很多条命令、语句及循环控制,然后一次性把这些命令执行完,这种通过文件执行脚本的方式,称为非交互的方式。
Shell脚本类似于DOS系统下的批处理程序。
用户可以在Shell脚本中敲入一系列的命令及命令语句组合。
这些命令、变量和流程控制语句等有机地结合起来就形成了一个功能强大的Shell脚本
1.3. 脚本语言的种类
1. Bourne shell
Bourne shell又包括Bourne shell (sh)、Korn shell (ksh)、Bourne Again Shell(bash)三种类型,重点是Bourne Again Shell (bash) 。
2. C shell
C shell又包括csh、tcsh两种类型。csh由Berkeley大学开发,随BSDUNIX发布,它的流程控制语句很像C语言,支持很多Bourne Shell所不支持的功能,例如:作业控制、别名、系统算术、命令历史、命令行编辑等。tcsh是csh的增 强版,加入了命令补全等功能,在FreeBSD、MacOSX等系统上替代了csh
Bourne Again Shell (bash)
Bourne Again Shell即bash由GNU项目组开发,主要目标是与POSIX标准保持一致,同时兼顾对sh的兼容,bash从csh 和ksh借鉴了很多功能,是各种Linux发行版默认配置的Shell,在Linux系统上的/bin/sh往往是指向/bin/bash的 符号链接。
虽然如此,bash和sh还是有很多的不同,一方面,bash扩展了一些命令和参数,另一方面,bash并不完 全和sh兼容,它们有些行为并不一致,但大多数企业运维 的情况下区别不大,特殊场景可以使用bash替代sh。
因为当时有很多厂商基于unix开发很多版本的系统 所有就产生了很多的不同的shell解释器
Shell脚本与php/perl/python语言的区别和优势?
shell脚本的优势在于处理操作系统底层的业务 (linux系统内部的应用都是shell脚本完成)因为有大量的linux系统命令为它做支撑。
2000多个命令都是shell脚本编程的有力支撑,特别是grep、awk、sed等。例如:一键软件安装、优化、监控报警脚本,常规的业务应用,shell开发更简单快速,符合运维的简单、易用、高效原则.
PHP、Python优势在于开发运维工具以及web界面的管理工具,web业务的开发等。处理一键软件安装、优化,报警脚本。常规业务的应用等php/python也是能够做到的。但是开发效率和复杂比用shell就差很多了。
PHP语言
PHP是网页程序语言,也是脚本语言。是一款更注 于Web页面开发(前端展示)的语言,例如: wordpress、dedecms、discuz等著名开源产品都是 用PHP语言开发的
Perl语言
Perl脚本语言,语法灵活、复杂,缺点是不易读, 团队协作困难,存世的大量相关程序软件(比如, xtrabackup热备工具、MySQL MHA集群高可用软件等 都有Perl语言的身影)。
Python语言
Python是当下流行的语言,不但可以用于脚本程序开发,也可实现Web程序开发(例如:CMDB管理系统),还可以做软件开发( OpenStack)、游戏开 发、大数据开发、移动端开发。
1.4.为什么学习shell
Linux底层核心
Linux运维工作常用的工具
自动化运维必备基础工具
提升工作效率
减少重复工作
shell不可替代
1.5 如何学好Shell编程
变量基础、条件表达式、if判断,for循环,while循环、case语句
循环控制命令 continue,break,exit 要能看懂别人的代码,掌握常见的各种语法,经常练习、经常写
从简单的判断循环开始做起
阅读、模仿,阅读,模仿、仔细分析、总结、文档
要有编程思维
找一本合适的教材、或者自己认真做的较为全面的笔记
核心
多练习-多思考-再练-在思考,坚持如此循环即可
大忌:不可拿来主义,可以模仿,但是要自己嚼烂了在吃下
学完shell 可解决企业中大部分脚本问题
2. shell脚本的规范
1、脚本存放固定目录 /server/scripts
2、开头加脚本解释器
3、附带作者及版权信息
4、脚本扩展名为*.sh
5、脚本中不用中文
6、成对的符号一次书写完成
7、循环格式一次性输入完成
8、循环格式要缩进
2.1 shell脚本的执行
1. bash script-name或sh script-name
这是当脚本文件本身没有可执行权限(即文件权限属性x 位为-号)时常使用的方法,或者脚本文件开头没有指定解释器时需要使用的方法
2. path/script-name或./script-name
指在当前路径下执行脚本(脚本要有执行权限),需要先将脚本文件的权限改为可执行(即文件权限属性加x 位),具体方法为chmod +x script-name。然后通过脚本绝对路径或相对路径就可以直接执行脚本了。
3. source script-name或. script-name
4. sh<script-name或cat scripts-name|sh
讲解执行方法区别
1 2 4 执行脚本时在命令行无法取到脚本中的内容
用3 执行时就可以取到脚本中的内容
[root@web01 scripts]# cat ceshi.sh
#!/bin/bash
user=`whoami`
[root@web01 scripts]# sh ceshi.sh
[root@web01 scripts]# echo $user
[root@web01 scripts]# source ceshi.sh
[root@web01 scripts]# echo $user
root
2.2 shell脚本执行过程
A脚本中放B脚本 那A脚本里的那个B脚本就是子shell脚本 A就是父shell脚本
还可以把命令行当成父shell,在命令行执行的脚本是子shell脚本,所以source ceshi.sh就是把子脚本的定义放到命令行中操作
3.shell变量
3.1 什么是变量?
在小学或初中时,我们开始接触数学方程式,例如:已知x=1,y=x+1,那么y等于多少? 在上述问题中,等号左边的x和y当时被称做未知数,但在Shell编程里就叫做变量名,等号右边的1和x+1则是变 量的内容(变量的值)。
注意,这里的等号符号被称为赋值,而不是等号。
3.2 变量的分类
变量可分为两类:环境变量(全局变量)和普通变量(局部变量)。
环境变量也可称为全局变量,可以在创建他们的Shell及其派生出来的任意子进程Shell中使用,环境变量又可分为自定义环境变量和bash内置的环境变量。
普通变量也可称为局部变量,只能在创建他们 的Shell函数或Shell脚本中使用。
普通变量一般由开发者在开发脚本程序时创建。
全局变量:环境变量 在父脚本中定义在子脚本中就可以使用
普通变量:局部变量 在命令行定义就在命令行使用 在脚本中定义就在脚本中使用
3.3 Shell环境变量介绍
环境变量一般是用export内置命令导出的变量,用于定义Shell的运行环境,保证Shell命令的正确执行。Shell通过环境变量来确定登录用户名、命令路径、终端类型、登录目录等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、Shell脚本和各类应用
3.3.1 操作Shell环境变量
1.显示环境变量
2.设置环境变量
3.取消环境变量
显示环境变量
显示:echo env
[root@bogon scripts]# echo $HOME
/root
[root@bogon scripts]# echo $SHELL
/bin/bash
[root@bogon scripts]# echo $UID
0
[root@bogon scripts]# cd -
/root
[root@bogon ~]# env|grep -i oldpwd
OLDPWD=/server/scripts
[root@bogon ~]# cd -
/server/scripts
[root@bogon scripts]# cd $OLDPWD
[root@bogon ~]# cd $OLDPWD
定义:export
export BOY=1
GIRL=2
export GIRL
declare -x 作用相当于export
[root@bogon scripts]# export BOY=1
[root@bogon scripts]# echo BOY
BOY
[root@bogon scripts]# echo $BOY
1
[root@bogon scripts]# GIRL=2
[root@bogon scripts]# export OLDGIRL
[root@bogon scripts]# echo $GIRL
2
删除:unset 取消变量
[root@bogon scripts]# export BOY=1
[root@bogon scripts]# echo $BOY
1
[root@bogon scripts]# unset BOY
[root@bogon scripts]# echo $BOY
3.3.2 shell环境变量如何永久生效
全局生效:
/etc/profile
/etc/bashrc
当前用户生效:
~/.bashrc
~/.bash_profile
Su – 切换用户的话会带着环境变量
[root@bogon scripts]# useradd haoge
[root@bogon scripts]# su – haoge
3.3.3 环境变量初始化与对应文件生效顺序
㈠ 登入shell(直接从终端登录)
/etc/profile 是登入shell启动后运行的第一个启动脚本
它只为登入shell运行;非登入shell不会引发这个脚本
登入shell加载启动脚本的顺序为:
/etc/profile → /etc/profile.d → ~/.bash_profile → ~/.bashrc → /etc/bashrc
每个调用的脚本会依次撤销前一个调用脚本中的改变,会覆盖前一个定义的变量
在退出登入shell时,我们还想执行某些任务,如清理历史命令、清除临时文件把这些任务放在.bash_logout文件
㈡ 非登入shell(用su切换过去)
非登入shell加载启动脚本的顺序:
.bashrc → /etc/bashrc → /etc/profile.d
3.4 shell普通变量介绍
普通变量也称局部变量,局部变量在用户当前Shell生存期的脚本中使用。例如,本地变量haoge的取值为bomc,这个值只在用户当前Shell生存期中有意义。如果在Shell中启动另一个进程或退出,变量hoage的值将无效。
3.4.1 操作shell普通变量
普通变量规范:
变量名=值
变量名:字母、下划线、数字,并且不能数字开头。
变量名不要用没有意义的字符串:
haoge_age 下划线连接单词
haogeAge 驼峰语法
HaogeAge 每个单词首字母都大写
=号:赋值符,两端没有空格,等号常用==
值:
不加引号 haoge_age=35 一般纯数字,简单连续的字符串也可以,但不推荐。
加单引号 haoge_age='35' 所见即所得,眼睛看到什么,输出或者使用就是什么。
加双引号 haoge_age="35" 除了纯数字以外,无特殊需求默认双引号,解析变量等。
加反引号 haoge_age=`date +%Y` 还可以用$(),将命令解析出结果
使用:
$变量名 通用
${变量名} 保护变量
举例:
db=1
echo ${db}_name
1_name
echo $db_name
空行
3.5 特殊变量
3.5.1 特殊位置变量
$0 获取当前执行shell脚本的文件名、如果执行脚本带路径,就包括脚本路径
$n 获取当前执行shell脚本的第n个参数值,当n为0时表示脚本的文件名,如果n大于9 则用大括号括起来 例如:{10} 接的参数以空格隔开
$# 获取当前执行Shell脚本后面接的参数的总个数
$* 获取当前shell脚本所有传参的参数,如果不加引号作用同$@相同,如果加上双引号"$*" 则表示将所有的参数视为一个字符串 相当于"$1$2$3"
$@ 获取当前shell脚本所有传参的参数,不加引号同$* 相同,加上双引号则表示把所有的参数视为不同的独立的字符串 相当于“$1” “$2” “$3”
$0
[root@shell scripts]# cat lianxi.sh
#!/bin/bash
echo $0
[root@shell scripts]# sh lianxi.sh
lianxi.sh
[root@shell scripts]# sh /server/scripts/lianxi.sh
/server/scripts/lianxi.sh
类似命令:
[root@shell scripts]# dirname /server/scripts/lianxi.sh
/server/scripts
[root@shell scripts]# basename /server/scripts/lianxi.sh
lianxi.sh
$n(n=任意数字)
[root@shell scripts]# tail -2 test2.sh
echo $0
echo $1
[root@shell scripts]# sh /server/scripts/test2.sh Haoge
/server/scripts/test2.sh
Haoge
[root@shell scripts]# tail -3 test2.sh
echo $0
echo $1
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
[root@shell scripts]# sh /server/scripts/test2.sh {a..z}
/server/scripts/test2.sh
a
a b c d e f g h i j k l m n o
$#
[root@shell scripts]# cat test2.sh
echo $#
[root@shell scripts]# sh test2.sh abc cba
2
应用:
if [ $# -ne 2 ];then
echo "Usage: $0 需要传递两个参数"
exit 1
fi
$ *
$@
[root@shell scripts]# set -- "I am" hao gege.
[root@shell scripts]# echo $1
I am
[root@shell scripts]# echo $2
hao
[root@shell scripts]# echo $3
gege.
[root@shell scripts]# echo $#
3
[root@shell scripts]# echo $*
I am hao gege.
[root@shell scripts]# echo $@
I am hao gege.
[root@shell scripts]# for n in "$*";do echo $n;done
I am hao gege.
[root@shell scripts]# for n in "$@";do echo $n;done
I am
hao
gege.
3.5.2 特殊进程状态变量
$? 获取执行上一个指令执行状态返回值 0为成功 非零失败
$$ 获取当前shell脚本的进程号PID
$! 获取上一个在后台工作脚本进程的进程号PID
$_ 获取在此之前执行命令或脚本的最后一个参数,相当于ESC .
$?
企业场景:
执行启动服务的程序
判断$?是否为0 ,为0就给出启动成功提示,非0可以给出启动失败的提示
$$
[root@shell scripts]# cat ceshi.sh
echo $$ > /tmp/ceshi.pid
sleep 10
企业应用:
获取进程号从而管理进程。
kill `cat /tmp/oldboy.pid`
$_
[root@shell scripts]# sh ceshi.sh fff ddd
[root@shell scripts]# echo $_
ddd
$!
[root@shell scripts]# sh ceshi.sh &
[1] 1338
[root@shell scripts]# echo $!
1338
[root@shell scripts]# cat /tmp/ceshi.pid
1338
3.6 变量子串
${#parameter } 返回变量长度
[root@shell scripts]# haoge="I am a Linux enthusiast"
[root@shell scripts]# echo ${haoge}
I am a Linux enthusiast
[root@shell scripts]# echo ${#haoge}
23
其他方式:获取字符串或变量内容长度的四种方法
[root@shell scripts]# echo ${#haoge}
23
[root@shell scripts]# echo ${haoge}|wc -L
23
[root@shell scripts]# expr length "$haoge"
23
[root@shell scripts]# echo ${haoge}|awk '{print length}'
23
${#parameter:offset}从parameter的offset位置到结尾
[root@shell scripts]# echo ${haoge:2}
am a Linux enthusiast
[root@shell scripts]# echo ${haoge:4}
a Linux enthusiast
${#parameter:offset:length}从parameter的offset位置开始截取长度为length的子串
[root@shell scripts]# echo ${haoge:2:4}
am a
[root@shell scripts]# echo ${haoge:2:2}
am
[root@shell scripts]# echo ${haoge:2:1}
a
${parameter#world}删除变量中的字符串:#开头; %结尾; ## %%最长匹配; # % 最短匹配
[root@shell scripts]# echo $haoge
abcABC123ABCabc
[root@shell scripts]# echo ${haoge#a*c}
ABC123ABCabc
[root@shell scripts]# echo ${haoge##a*c}
[root@shell scripts]# echo ${haoge%a*c}
abcABC123ABC
[root@shell scripts]# echo ${haoge%%a*c}
${parameter/pattern/string}替换变量中的字符:/ 替换匹配到的第一个pattern
[root@shell scripts]# echo ${haoge}
abcABC123ABCabc
[root@shell scripts]# echo ${haoge/abc/haoge}
haogeABC123ABCabc
${parameter//pattern/string}替换变量中的字符:/ / 替换匹配所有的pattern
[root@shell scripts]# echo ${haoge}
abcABC123ABCabc
[root@shell scripts]# echo ${haoge//abc/haoge}
haogeABC123ABChaoge
3.7 特殊变量扩展
${parameter:-word} 冒号可以省略
[root@shell scripts]# result=${test:-haoge}
[root@shell scripts]# echo $result
haoge
[root@shell scripts]# echo $test
如果test有赋值
[root@shell scripts]# test=yuyu
[root@shell scripts]# result=${test:-haoge}
[root@shell scripts]# echo $result
yuyu
[root@shell scripts]# echo $test
yuyu
${parameter:=word}
用法比${parameter:-word}用法多一个给变量内容里的变量赋值。
[root@shell scripts]# unset test
[root@shell scripts]# result=${test:=haoge}
[root@shell scripts]# echo $result
haoge
[root@shell scripts]# echo $test
haoge
${parameter:?word}用法。当未赋值时word当作标准错误输出
[root@shell scripts]# unset test
[root@shell scripts]# result=${test:?变量为负值}
-bash: test: 变量为负值
${parameter:+word}用法。
和${parameter:-word}用法相反
[root@shell scripts]# unset test
[root@shell scripts]# result=${test:+haoge}
[root@shell scripts]# echo $result
[root@shell scripts]# test=1
[root@shell scripts]# result=${test:+haoge}
[root@shell scripts]# echo $result
haoge
[root@shell scripts]# echo $test
1
4. 变量的数值运算
4.1 整数运算符
(())
[root@shell ~]# a=11
[root@shell ~]# echo $((a+1))
12
[root@shell ~]# echo $(($a+1 ))
12
let
[root@shell ~]# i=1
[root@shell ~]# i=i+8
[root@shell ~]# echo $i
i+8
[root@shell ~]# i=1
[root@shell ~]# let i=i+8
[root@shell ~]# echo $i
9
案例:
sum=0
while read line
do
size=`echo $line|awk '{print $10}'|grep -v -`
let sum+=size
done<$1
echo $sum
let sum+=size 就是把sum与size两变量的值相加赋予新的sum
[root@shell scripts]# sum=0
[root@shell scripts]# a=10
[root@shell scripts]# let sum+=a
[root@shell scripts]# echo $sum
10
expr
数字跟加号中间要有空格
[root@oldboy ~]# expr 1 + 1
2
[root@oldboy ~]# expr 1 + 3
4
[root@oldboy ~]# expr 1+3
1+3
[root@oldboy ~]# expr 1 + 3
4
[root@oldboy ~]# expr 1 + 3
4
$[]
[root@shell scripts]# echo $[1+1]
2
[root@shell scripts]# echo $[1 + 1 ]
2
[root@shell scripts]# echo $[1-1]
0
declare
[root@shell scripts]# a=10
[root@shell scripts]# declare -i b=$a+10
[root@shell scripts]# echo $b
20
[root@shell scripts]# a=1
[root@shell scripts]# declare b=$a+10
[root@shell scripts]# echo $b
11
declare -i 声明是整数型变量 +i取消整数型属性
[root@shell scripts]# declare -i wa
[root@shell scripts]# wa="haoge"
[root@shell scripts]# echo $wa
0
[root@shell scripts]# wa=123456
[root@shell scripts]# echo $wa
123456
[root@shell scripts]# declare +i wa
[root@shell scripts]# wa="haoge"
[root@shell scripts]# echo $wa
haoge
4.2 整数及小数的运算符
bc
yum install bc -y
[root@shell ~]# echo 1+2|bc
3
[root@shell ~]# echo 11-2|bc
9
小数
echo "scale=2;6/4" |bc
scale是值小数点后的长度
awk
[root@shell ~]# echo 11.3 2.8|awk '{print $1-$2}'
8.5
python
echo "print 5.0/2" |python
4.3 expr特殊功效
判断变量是否是整数(返回0是整数 返回其他不是整数)
[root@shell scripts]# a=1
[root@shell scripts]# expr $a + 1 &>/dev/null
[root@shell scripts]# echo $?
0
[root@shell scripts]# a=1.1
[root@shell scripts]# expr $a + 1 &>/dev/null
[root@shell scripts]# echo $?
2
计算字符串长度
[root@shell scripts]# a=abc
[root@shell scripts]# expr length "$a"
3
[root@shell scripts]# a=abc4444
[root@shell scripts]# expr length "$a"
7
判断文件扩展名
if expr "$1" : ".*\.txt$" >/dev/null ; then
echo "你输入的是$1"
else
echo "对不起,格式错误"
fi
[root@shell scripts]# sh judge.sh haoge.txt
你输入的是haoge.txt
[root@shell scripts]# sh judge.sh haoge.log
对不起,格式错误
5. read 和用户交互,接收用户的输入
-p 提示
-t 超时时间
-s 不显示终端的任何输入
[root@shell scripts]# read -p "请输入一个数字:" num
请输入一个数字:300
[root@shell scripts]# echo $num
300
相当于num=300
练习题
实现一个加减乘除等功能的计算器
要求
1)必须输入两个东西
2)必须为数字
3)运算