Day01 Shell脚本编程

一、shell环境及特性

1.1 什么是shell

解释器:负责向内核翻译及传达用户/程序指令
解释器 车
shell 汽车
bash 宝马、奔驰、法拉利

1.1.1 /etc/shells

文件里面的内容就是系统已安装的解释器

1.1.2 usermod -s /bin/tsh zhangsan

修改老用户的默认解释器

1.1.3 useradd -s /bin/tsh zhangsan

创建新用户时指定默认解释器

1.2 Bash基本特性

1.2.1 快捷键

ctrl+l清屏
ctrl+c终止当前运行的程序
ctrl+a移动光标到行首
ctrl+e移动光标到行尾
ctrl+w删除当前光标前面的一个单词
esc+d删除当前光标后面的一个单词
ctrl+u删除当前光标到行首的所有内容
ctrl+k删除当前光标到行尾的所有内容
ctrl+f向前移动一个字符
ctrl+b向后移动一个字符
alt+b 向前移动一个单词
alt+f 向后移动一个单词

1.2.2 tab键补全

RHEL7.2才支持补齐选项,老版本可通过bash-completion包提供选项补齐的功能

1.2.3 命令历史

grep HISTSIZE /etc/profile#查看历史命令默认保存条数
history | wc -l#查看当前使用了多少条命令
!100#执行第100条命令
!cat#从后到前,查找最近执行的cat命令
history -c#清除历史命令
~/.bash_history

1.2.4 命令别名

alias
unalias
/etc/bashrc
~/.bashrc

1.2.5 标准输入输出

标准输出&1
错误输出&2
标准输入&0

1.2.6 重定向

对脚本来说,重定向非常重要,相当于给执行脚本做了个日志记录
1>正确输出 1>>正确追加输出
2>错误输出 2>>错误追加输出
&>将正常输出、错误输出重定向同一个文件

/dev/null 2>&1 相当于1>/dev/null 2>/dev/null。是将标准出错重定向到标准输出,最后一个&表示取标准设备。
echo 'error' >&2 把echo出来的结果 重定向到 错误输出.
<重定向输入

1.2.7 管道操作

在linux里面管道非常重要!!!
把前一个命令的输出作为给后面的命令的输入
因为linux命令设计的原则是3S(simple、small、speed),软件越大启动越慢、漏洞越多。管道具体使用上就是用来组合多个命令,来实现复杂的功能
yum list|grep abc|wc -l
echo "content" | mail -s "title" receipt 缺点是邮件内容不能写太多,优点是不用另外创建文件
mail -s "title" receipt < mail.txt 缺点是需要先创建文件,优点是可以写很多内容

二、Shell脚本设计

2.1 新建文件

扩展名是.sh

2.2 写代码

顶格第一行必须是#!/bin/bash,表示该脚本指定由bash作为脚本解释器
#为注释符,注释可以写时间、版本、功能、联系人

2.3 给权限

chmod +x 脚本名

2.4 执行脚本

./脚本名#相对路径
/root/脚本名#绝对路径
bash 脚本名#指定解释器,即使脚本没有执行权限,也同样能执行脚本
上面的执行方式都会开启子进程
但是注意!source 脚本名是不会开启子进程的。
在特例中,比如脚本中只有一行exit,执行脚本后会退出当前bash

$PATH 命令搜索路径

三、写脚本

3.1 打印输出hello the world

#!/bin/bash
echo "hello the word"

3.2自动配置yum源

#!/bin/bash
if [ -d /etc/yum.repos.d ];then
rm -fr /etc/yum.repos.d/*
echo '[dvd]
name=rhel
baseurl=http://192.168.4.254/rhel7
gpgcheck=0' >/etc/yum.repos.d/dvd.repo
else
mkdir -p /etc/yum.repos.d/
echo '[dvd]
name=rhel
baseurl=http://192.168.4.254/rhel7
gpgcheck=0' >/etc/yum.repos.d/dvd.repo
fi

3.3 自动安装vsftpd

#!/bin/bash
yum clean all >/dev/null
yum -y install vsftpd 2>/var/log/ins_vsftpd_err.log >/dev/null
systemctl restart vsftpd && systemctl enable vsftpd >/dev/null

3.4 创建用户脚本

#!/bin/bash
read -p "请输入用户名:" name
#关闭回显
stty -echo
read -p "请输入密码:" pass
#打开回显
stty echo
useradd $name
echo $pass | passwd --stdin $name

3.5 每周五备份一次/var/log,使用tar备份到/root目录下

echo '03 03 5 tar -czf /root/log-$(date+%F).tar.gz /var/log' >>/var/spool/cron/root

3.6 每分钟检测当前计算机登录的用户数量,如果大于2,则发邮件报警

思路:如何检测登录用户数量?如何判断大于2?如何发邮件?
#!/bin/bash
#判断本机登录的用户数是否大于2,如果大于2,则发邮件给root
num=who|wc -l
[ $num -gt 2 ] && mail -s Error root #mail.txt是要发的邮件内容

3.7 判断有cd目录则挂载光盘;没有cd目录则创建目录并挂载光盘

[ -d /root/cd ] && mount /ISO/rhel7.iso /cd || mkdir /cd;mount /ISO/rhel7.iso /cd
[ -d /root/cd ] || mkdir /cd && mount /ISO/rhel7.iso /cd
[ ! -d /root/cd ] && mkdir /cd;mount /ISO/rhel7.iso /cd

3.8 计算1+2+3+4...+100的和

思路:只关心最后得出的和。如何输出1..100?输出的值存入另一个变量?另一个变量存储最后得出的和
#!/bin/bash
j=0
for i in {1..100}
do
let j+=i
done
echo $j

3.9 将/var/log下的每个文件,单独打包,保存到/tmp

思路:如何显示每个文件?如何打包并保存?
#!/bin/bash
for n in ls /var/log
do
tar -zcf /tmp/$n.tar.gz /var/log/$n &>/dev/null
done

3.10 输入数字求和,直到输入0后结束并输出和

思路:读取键盘输入?求和并存在另一个变量内?如果输入0则结束循环并输出和
#!/bin/bash
RESULT=0
while :
do
read -p "请输入一个数[0结束]:" NUM
[ $NUM -eq 0 ] && break
let RESULT+=$NUM
done
echo $RESULT

3.11 打印9*9乘法表

实际屏幕输出:
11=1
2
1=2 22=4
3
1=3 32=6 33=9
......
91=9 92=18 93=27 94=36 95=45 96=54 97=63 98=72 9*9=81 
思路:i={1..9} j={?} 要打出三角形,核心是i<=j

脚本:
#!/bin/bash
for j in {1..9}
do
for i in {1..9}
do
echo -en "$i$j=$[ij]\t"
[ $i -eq $j ] && break
done
echo
done

#!/bin/bash
for j in {1..9}
do
for i in seq $j
do
echo -en "$i$j=$[ij]\t"
done
echo
done

3.12 打印国际象棋的棋盘(8*8)

思路:棋盘的格式是黑白相间
脚本:
#!/bin/bash
for n in {1..4}
do
for i in {1..4}
do
echo -en "\033[44m \033[0m"
echo -en "\033[45m \033[0m"
done
echo
for j in {1..4}
do
echo -en "\033[45m \033[0m"
echo -en "\033[44m \033[0m"
done
echo
done
更优秀的代码:
#!/bin/bash
color(){
for n in {1..4}
do
echo -en "\033[4$1m \033[0m"
echo -en "\033[4$2m \033[0m"
done
}
for i in {1..8}
do
y=$[i%2]
[ $y -eq 1 ] && color 7 0 || color 0 7
echo
done

3.13 猴子摘了n个香蕉。第1天吃一半,没吃饱又吃了一个;第2天又吃一半,没吃饱又吃了一个;第...吃到第9天只剩下1个香蕉。请问n等以几?

思路:前一天的数量y等于今天的数量(x+1)2
x=1
for i in {1..8}
x=$[(x+1)
2]

3.14 提示用户显示一个数的求和,输入任意数,则输出任意数的求和;如果不输入值,则显示1+...100的和

思路:如何计算1+...x的和?不输入值该如何处理?
#!/bin/bash
sum=0
read -p "请输入一个数:" num
num=${num:-100}
for i in seq $num
do 
let sum+=i 
done 
echo "从1到${num}的求和值为:$sum"
exit

3.15 计算机随机生成3个数,把3个数从小到大输出来

思路:num1存最小值,num2存中间,num3存最大值,tmp作为中间变量。有多少种可能呢?
num1>num2>num3
num1< num2< num3
num2 < num3
num2
首先if判断num1和num2比大小。如果num1大,则把num1和num2交换,保证num1存放的是小值;如果num2大,则不做操作,结束这个判断
然后再来个if判断num1和num3比大小。如果num1大,则把num1和num3交换,保证num1存放的是最小值;如果num3大,则不做操作,结束这个判断
最后的if判断num2和num3比大小。如果num2大,则把num2和num3交换,保证num3存放的是最大值;如果num3大,则不做操作,结束这个判断。
从小到大输出$num1 $num2 $num3

#!/bin/bash
#num1存最小值,num2存中间,num3存最大值
num1=$RANDOM
num2=$RANDOM
num3=$RANDOM
tmp=0
if [ $num1 -gt $num2 ];then
tmp=$num2;num2=$num1;num1=$tmp
fi

if [ $num1 -gt $num3 ];then
tmp=$num1;num1=$num3;num3=$tmp
fi

if [ $num2 -gt $num3 ];then
tmp=$num3;num3=$num2;num2=$tmp
fi
echo $num1 $num2 $num3

四、变量

以固定名称来存放可能会变化的值

4.1 定义规则

若指定的变量名存在,则相当于给变量赋值
等号两边不能有空格
只能用数字、字母和下划线组成
不能以数字开头

4.2 赋值

4.2.1 直接赋值

变量名=变量值
FROM=/etc/

4.2.2 通过read获取变量值

read -p "提示" 变量名#只定义变量名,不赋值。由使用该命令的人来赋值

4.2.3 使用命令行参数

使用位置变量$1、$2等

4.2.4 管道接收命令的输出

通过管道|把前面命令的输出作为现在命令的输入

4.3 引用

$FROM

4.4 查看

echo $FROM
echo ${FROM}

4.5 环境变量

配置文件:/etc/profile、~/.bashrc
PATH
HOME
USER
UID
HOSTNAME
PS1 一级提示符
PS2 二级提示符

4.6 预定义变量

$0:脚本自身的名字
$1:位置变量1
$2:位置变量2
$:所有变量
$ @ :所有变量。
$
和$@都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。 
但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。
$#:所有变量的数量
$$:脚本运行后的PID
$!:显示最后一个被放到后台的进程PID
$?:上一条命令执行状态,值等于0为正确,值非0就是错误

4.7局部变量和全局变量

4.7.1 局部变量

自定义变量默认就是局部变量
存在于脚本函数(function)中的变量也是局部变量。
要以 local 变量名方式进行声明,使之只在本函数作用域内有效,防止变量在函数中的命名与变量外部程序中变量重名造成程序异常。
局部变量默认只在当前shell环境中有效,无法在子shell环境中使用
可以通过export命令将局部变量声明为全局变量

4.7.2 全局变量

系统变量默认就是全局变量
全局变量在当前shell环境及子、孙等shell环境中有效
/etc/profile
export 变量名#将局部变量声明为全局变量
export -n 变量名#取消声明

五、单引号&双引号&反引号

5.1 双引号""

双引号可以界定一个完整的字符串
echo a b
echo "a b"

5.2 单引号''

单引号可以界定一个完整的字符串,而且可以屏蔽特殊符号($\ ),原封不动输出。

5.3 反引号 ``

命令 仅可以放命令,提取的是命令的结果
$(命令) 仅可以放命令,提取的是命令的结果



本文转自 goldwinner 51CTO博客,原文链接:http://blog.51cto.com/355665/2068827,如需转载请自行联系原作者

你可能感兴趣的:(shell,运维,操作系统)