Shell脚本基础

Shell脚本——提前设计可执行语句,用来完成特定任务的文件。(命令的堆积)

          ——解释型程序;顺序、批量执行

常见脚本语言:Bash Shell/Python/Perl/Ruby/JSP/PHP/ASP/CGI/JavaScript……

规范Shell脚本的一般组成 :

#!环境声明    //使用哪种解释器,作者信息等。sha-bang调用标记

#注释文本   //一般脚本超过10行,默认要进行注释(注释信息可包括步骤、思路、用途、变量含义等)

可执行代码

脚本的创建过程

Ø 1)明确任务需求:按自然语言拆分小步骤;按顺序整理好(先做什么,后做什么)

Ø 2)编写代码文件:每一个步骤怎么实现;转换成命令行保存到脚本文件

Ø 3)测试并完善:运行脚本,并根据结果排除错误;代码优化、用户友好处理

Shell脚本的执行方式

方法一:作为“命令字”:指定脚本文件的路径,前提是有x权限

需要权限x(chmod赋予);chmod +x 脚本文件路径

绝对路径:#/脚本文件路径

相对路径:#cd 脚本文件路径    #./脚本文件

方法二:作为“参数”:不需要脚本文件有x权限:

会启动子进程(HISTSIZE=2):bash 脚本文件路径   或sh 脚本文件路径

不会启动子进程:脚本文件路径     或 source 脚本文件路径

调试Shell脚本,主要途径:直接观察执行中的输出、报错信息

    通过sh -x开启调试模式

    在可能出错的地方设置echo

###########################################################################

示例:编写一个面世问候 /root/helloworld.sh 脚本

1.编写脚本代码  # vim /root/helloworld.sh

              echo  “Hello World!!”    //可执行代码

# ls -l /root/helloworld.sh

-rw-r--r--. 1 root root 76 8月  29 10:45 /root/helloworld.sh

2.添加x执行权限 # chmod a+x 1.sh        #赋予所有人执行权限

# ls -l /root/helloworld.sh

-rwxr-xr-x. 1 root root 76 8月  29 10:45 /root/helloworld.sh

3.运行脚本测试 # /root/helloworld.sh

如果是在当前路径运行此文件程序 #  ./helloworld.sh ###########################################################################

示例:依次输出以下系统信息(红帽系统版本、内核版本、当前主机名)

编写脚本代码:  #vim /root/sysinfo.sh

                  #!/bin/bash

                  cat /etc/redhat-release 

                  uname -r

                  hostname

脚本运行及调试:(所有人)添加执行权限   #chmod +x /root/sysinfo.sh

                独立运行               #/root/sysinfo.sh

通过sh执行脚本代码,结合-x选项,可以调试脚本代码(此操作不需要再单独对文件添加执行权限)   #sh -x /root/sysinfo.sh

###############################################################################

示例:快速为新装的客户机配置YUM仓库;快速为新装的客户机搭好vsftpd服务

#!/bin/bash

echo "准备配置yum源..."

rm -rf /etc/yum.repos.d/*.repo               //清理配置目录

echo "

[rh7dvd]

name=rh7dvd

baseurl=http://192.168.4.254/rh7dvd/

enabled=1

gpgcheck=0

" > /etc/yum.repos.d/rh7dvd.repo               //新建仓库配置文件

echo "配置完成。软件包数量如下:"

yum repolist | tail -1

echo "准备安装软件..."

yum -y install vsftpd &> /dev/null              //装包,忽略输出

systemctl start vsftpd &> /dev/null

systemctl enable vsftpd > /dev/null

echo "安装完成"

echo "启动服务完成"

###############################################################################

使用变量,增加脚本的适应环境的能力

变量:以固定的名称存放的可能会变化的值   可用生活中的容器(杯子)来比喻,用固定的字符存储变化的数据。 

Ø 方便以固定名称重复使用某个值

Ø 提高对任务需求、运行环境变化的适应能力

定义/赋值变量

Ø 变量名=变量值

设置变量时的注意事项

– 若指定的变量名已存在,相当于为此变量重新赋值

– 变量名相同时候赋值的生效

– 等号两边不要有空格

– 变量名由字母/数字/下划线组成,区分大小写

– 变量名不能以数字开头,不要使用关键字和特殊字符

查看/引用变量

Ø 引用变量值:$变量名

Ø 查看变量值:echo $变量名、 echo ${变量名}

未定义的变量为空值   以{}界定易混淆名称,一般用于嵌套

a=11, $ab为空,调用要使用${a}b

echo $USER 输出用户名

取消变量

Ø 退出定义变量的Shell环境时,变量会自动失效

Ø 手动取消:unset 变量名

/dev/null是Linux中专门用来存放,不要的数据或输出信息的设备。

SHELL变量--shell的变量是弱类型的变量

###############################################################################

示例:创建用户脚本,用户名利用变量user实现

1)编写脚本代码# vim /root/user.sh

#!/bin/bash

read -p '请输入您要创建的用户名:' user     #为user变量赋值

read -p '请输入您要设置的密码:' pass       #为pass变量赋值

useradd=$user                               #调用user变量的值

echo 用户$user创建成功                   

echo $pass |passwd --stdin $user &> /dev/null  #调用pass变量的值

echo 用户$user密码设置成功

2)添加x执行权限 # chmod  +x  /root/user.sh

3)测试 /root/user.sh 脚本

###############################################################################

变量的种类

根据存储类型分类

Ø 整数型、浮点型、双精度浮点型、字符型……

Ø Shell脚本语言对存储类型要求较松散

根据变量的用途不同区分

类型

说明

环境变量

变量名一般都大写,由系统维护,用来设置用户/系统环境,只有个别变量用户可以直接更改

位置变量

bash内置,存储执行脚本时提供的命令行参数

预定义变量

bash内置,一类有特殊用途的变量,可直接调用,但不能直接赋值或修改

自定义变量

由用户自主设置、修改及使用

环境变量——写在profile的变量

配置文件:/etc/profile、~/.bash_profile

相关操作:env:列出所有的环境变量

  set:列出所有变量

常见的环境变量:PWD(当前工作目录变量)PATH(命令搜索路径变量)、USER(用户名变量)、LOGNAME、UID(用户ID号);SHELL(当前使用的shell变量)、HOME(用户家目录变量)、PS1(命令提示符)、PS2……

PATH变量应用:在Linux执行大多数命令时,都要去PATH变量值当中去寻找该命令的程序文件,能够找到就执行,不能找到就告诉你找不到该命令

+++++++++++++++++++++++++++++++++++++++++++++

把自己编写的脚本,设置成执行的时候,像执行系统命令一样执行。

#echo  $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

#mkdir  /root/bin

#cp  /shell/checkip.sh  /root/bin/checkip

#chmod  +x  /root/bin/checkip

#checkip   172.40.50.117

或用软链接方式将脚本放入PATH路径下 ln -s ./a root/bin/a

+++++++++++++++++

题:执行一条命令出现“命令未找到”的原因?

1、输入有误; 2、该命令未安装;  3、该命令没有在PATH路径下。

位置变量

使用位置变量可以取得在执行脚本时提供的命令行参数:

    表示为 $n,n为序号    $1、$2、.. .. ${10}、${11}、.. ..

用于免交互传递值(适用于脚本熟练者)

示例:# vim 2.sh

 #!/bin/bash

 head  -$1  $2

 cat  -n  $2  |  head  -$1

 [root@server0 ~]# chmod +x  2.sh

[root@server0 ~]# ./2.sh   3  /etc/passwd   #输出/etc/passwd前3行,并标示行号

快速添加用户,并设置好登录密码

#!/bin/bash

echo "一共提供了$#个参数"

useradd=$1 2> /tmp/err/log

echo 用户$1创建成功  

echo $2 |passwd --stdin $1 &> /dev/null

echo 用户$1密码设置成功

# /root/user.sh nsd01 123456

#!/bain/bash

for i in {1..10}

 do 

useradd user$i    2>>user.log

echo "123456" |passwd --stdin user$i > /dev/null   

 done

问题:已存在用户不修改密码,使用if判断

#chmod +x test1.sh

++++++++++++++++++++++++

预定义变量:用来保存脚本程序的执行信息

直接使用这些变量;不能直接为这些变量赋值

变量名

含义

$0

当前所在的进程或脚本名

$?

 查看上一个命令退出后的状态值,0表示正常,其他值异常

$#

统计已加载的位置变量的个数

$*

输出所有位置变量的值

$$

返回当前进程的PID号

$($#-1):倒数第二个参数

例1:# cat /etc/redhat-release

# echo $?      #判断上一条命令,是否成功执行,

               0代表上一个命令执行成功,非0代表上一个命令执行失败

#vim test4.sh  

#!/bin/bash

echo $0 显示脚本的名称

echo $1 显示第一个参数

echo $2 显示第二个参数

echo $3 显示第三个参数

echo $* 显示所有参数

echo $# 统计参数有多少个

# chmod +x test4.sh

# ./test4.sh a b c 1 8 7

###############################################################################

扩展赋值操作

区分三种定界符

定界符

作用

 

双引号“”

允许扩展,以$引用其他变量,引用整体,支持特殊符号(整体中有调用参数时不影响调用结果)

echo a b c    != echo "a b c"

echo "abc"    == echo abc

单引号‘’

禁用扩展,即便$也视为普通字符,

引用整体,屏蔽特殊含义,原样输出,不用于调取参数

echo 'a b c'  == echo "a b c"

#echo "\$a"    == echo '$a'

echo '13$a'   != echo "13$a"

反撇号``

引用命令,提取命令的执行结果,只在双引号下使用才能显示其含义

 

每周五,把/var/log备份一次

crontab -e

01 03 * * 5 tar -czf log-`date +%Y%m%d`.tar.gz /var/log

$()

与反撇号``等效,但$()更方便嵌套使用,将命令的输出结果作为参数

 

 

read 产生交互(降低脚本的使用难度),写脚本时定义变量不赋值,运行脚本时,从键盘读入用户输入的变量值,完成赋值

格式:read [-p '屏幕输出的提示信息'赋值的变量名     -p可选,-t可指定超时秒数

终端显示控制:stty -echo:关闭终端输出(无显示)

  stty echo:恢复终端输出(显示)

修改制定用户的密码,用户名和密码由用户输入

#vim test6.sh                                        //创建一个测试脚本

#!/bin/bash

read -p "请输入用户名:"  user                         //读取用户名

stty -echo                                             //关闭回显 

read -p "请输入密码:"    pass                          //读取密码      

stty echo                                               //恢复回显

echo ""                                      //恢复回显后补一个空行

useradd $name 2> /tmp/err/log

echo $pass |passwd --stdin $user

+++++++++++++++++++++++++++++

rpm -q  httpd ||  yum -y  install httpd > /dev/null

service  httpdd  start ;  chkconfig  httpd  on

+++++++++++++++++++++++++++++++++++++

变量的作用范围

局部变量:(仅当前有效的变量)

新定义的变量默认只在当前Shell环境中有效

  无法在子Shell环境中使用

全局变量:(当前及所有子进程都有效的变量)

全局变量在当前Shell及子Shell环境中均有效

  使用export可将局部变量声明为全局变量

export 局部变量名[=变量值]…:为局部变量添加全局属性

export -n 全局变量名…:取消指定变量的全局属性

永久修改全局变量: /etc/profile

示例:

# SCHOOL=”Tarena IT Group.”

# sh                         //进入子Shell环境

# echo $SCHOOL              //无此变量,输出空行

sh-4.2# exit                //返回原Shell环境

# export SCHOOL             //声明为全局变量

# sh                         //再次进入子Shell

sh-4.2# echo $SCHOOL         //可成功使用该变量

Tarena IT Group.

 

 

 

 

 

 

 

 

 

 

数值运算

整数运算

四则运算符号:  +   -   *   /

取余数运算(求模)  num1%num2    

计算命令: $[]    $(())    expr    let   bc

$[]算式替换:使用$[]或$(())表达式

格式:$[整数1 运算符 整数2 …]

乘法操作*无需转义,运算符两侧可以无空格

引用变量可省略$符号;计算结果替换表达式本身,可结合echo命令输出。

echo $[ num1   运算符   num2  ]

echo $((num1   运算符   num2))

expr运算工具:计算指定的表达式,并输出结果

格式:expr 整数1 运算符 整数2…

参与运算的整数值与运算操作符之间需要以空格分开,引用变量时必须加$符号。

类型

运算符

示例(X、Y为整数)

加法

+

expr $X + $Y

减法

-

expr $X - $Y

乘法

\*

expr $X \* $Y      备注:乘法操作应用\*转义,避免被作为Shell通配符

除法

expr $X / $Y

取余数

expr $X % $Y

取10以内的随机数:# expr $RANDOM % 10     $RANDOM产生随机数

let命令格式:let  变量名++let  变量名--       结合echo命令查看结果

自加运算   ++   自己加1之后把计算结果赋值给自己

自减运算    --   自己减1之后把计算结果赋值给自己

可以自定义自加或自减的步长:+=  、 -=

简写表达式

完整表达式

示例(x=3)

i++

i=i+1

let x++     echo $x

i--

i=i-1

let x+=4    echo  $x

i+=2

i=i+2

 

i-=2

i=i-2

 

i*=2

i=i*2

 

i/=2

i=i/2

 

i%=2

i=i%2

 

# let y=X+22      # echo $y  

浮点数运算 bc    ——

交互式:# bc    //按quit退出交互计算器

非交互式:将需要运算的表达式通过管道操作交给bc运算。注意,小数位的长度可采用scale=N限制,除此以外也受参与运算的数值的小数位影响。

# echo "scale=2;3/4" | bc

# echo "1+2" | bc               

bc支持逻辑运算>  <  <= == !=...

# echo "1>3" |bc  对是1,错是0

小数运算

整数运算的局限性:

Bash内建机制仅支持整数值运算:expr命令、$[]算式替换不支持小数运算

使用bc实现小数运算

多数Linux系统默认安装此工具:支持高精度的数值运算

          直接运行bc可进入交互式运算界面,quit退出

          设置scale=n可给小数位

结合管道向bc发送表达式:多个表达式以分号分隔

       通过echo命令+管道传递要计算的表达式

小数值的比较

基本用法:echo “数值1 比较符 数值2” |bc

          如果表达式成立,则返回的计算结果为1,否则返回0

          常见比较操作:>、>=、<、<=、==、!=

x=`echo  "1.23 +  2.67"  |  bc`        echo $x

条件测试

Shell脚本的智能化:使Shell脚本获得识别能力?

                    为命令的执行提供最直接的识别依据

文件或目录的读/写等状态

数值的大小

字符串是否匹配

多条件组合

表达式:值1  符号  值2

Shell测试的依据

命令行/程序的退出状态值$?

Ø 值为0,表示执行成功

Ø 值不为0,还未执行异常或失败

在脚本中自定义退出状态值

Ø 以退出之前最后一条命令的$?作为脚本的退出状态值

Ø 也可以自行替换,添加exit整数

几种可用的测试方式

Ø 正常的命令行

Ø test -选项 参数……

Ø [ 测试表达式 ]

表达式两边至少要留一个空格。条件测试操作本身不显示出任何信息。测试的条件是否成立主要体现在命令执行后的返回状态(即 $?),所以可以在测试后查看变量$?的值来做出判断,或者结合&&、||等逻辑操作显示出结果(或作其他操作) 。

创建一个以当日日期结尾的文件

# mkdir mydir-$(date +%F)

# mkdir $(hostname)-$(date +%F)

# tar -czf log-`date +%Y%m%d`.tar.gz 文件或目录  (按当前日期)打包文件或目录            

字符比较

操作符

含义

示例

[操作符 字符串]

-z

检查变量的值是否未设置(空值)

[ -z "$var" ] && echo "空值" || echo "非空值"  未对变量赋值,则为空

[ ! -z $var1 ]测试var1是否为非空

-n

字符串的值不为空

(相当于!-z

[ -n "$var" ]

判断$var变量是否有值    

[字符串1 操作符 字符串2]

==

两个字符串相同

[ $USER == 'root' ]  echo $? 

!=

两个字符串不相同(取反

 

整数值比较

操作符

含义

示例

[整数值1 

操作符 

整数值2]

 

注:参与比较的必须是整数(可以调用变量),比较非整数值时会出错

-eq

等于(equal)

[ $X -eq 20 ] && echo "相等" || echo "不相等"

-ne

不等于(not equal)

 

-ge

大于等于

(greater or equal)

[ $X -ge 10 ] && echo "大于或等于" || echo "否"

-le

等于

(less or equal)

检查登录用户数是否不超过5个:[ $(who | wc -l) -gt 5 ] && echo "超过了" || echo "没超过"

[ $X -le 10 ] && echo "小于或等于" || echo "否"

-gt

大于(greater than)

[ $X -gt 10 ] && echo "大于" || echo "否"

-lt

小于(less than)

[ $X -lt 10 ] && echo "小于" || echo "否"

文件状态测试常用选项

操作符

含义

示例

 

 

 

 

 

 

 

 

 

 

[操作符 

文件或目录]

-e

判断对象(文件或目录)是否存在(exist)若存在则结果为真    

[ -e "/usr/src/" ] && echo "存在" || echo "不存在"

-d

判断对象是否为目录(directory)是则为真

[ -d "/usr/src/" ] && echo "是目录" || echo "不是目录"

-f

判断对象是否为一般文件(file)是则为真   

[ -f "/usr/src/" ] && echo "是文件" || echo "不是文件"

-r

判断对象(文件或目录)是否有可读(Read)权限,是则为真

此测试中,无论文件是否设置r/w权限,root都可读;x权限取决于文件本身、文件系统级的控制,root或普通用户都适用。

1)复制一个文件做测试:

# cp install.log /tmp/rtest.txt          

2)去掉需要测试的权限:

# chmod -r|w|x /tmp/rtest.txt    

3)测试root与普通用户:        

# [ -r "/tmp/rtest.txt" ] && echo "可读" || echo "不可读"

-w

判断对象(文件或目录)是否有可写(Write)权限,是则为真

-x

判断对象(文件或目录)是否有可执行(eXcute)权限,是则为真

-s 

判断文件大小非0时为真

  

 

-c

判断文件为字符特殊文件为真

 

 

-b

判断文件为块特殊文件为真

 

 

-t

当文件描述符(默认为1)指定的设备为终端时为真

 

需要注意的一些小细节

1) [ 、] 、==、!= 符号左右都需要有空格

2)引号、分号这些都是英文

3)字符串最好用双引号括起来 

 

#!/bin/bash

login_num=`who |wc -l`  #反引号

[ $login_num -gt 5 ]&&mail -s warning root <警告文件路径

制定计划任务

#crontab -e

*/15 * * * *  /var/tmp/test8.sh

 

监控脚本:ps aux 、free、uptime

内存,磁盘,CPU,进程数量

使用uptime查看(相当于top的最上边一行),先查看电脑CPU是几核的,1核的满负载是1,2核的满负载是2

示例:每分钟判断电脑的进程数量,大于X,就报警

#!/bin/bash

num=`ps aux |wc -l`

[ $num -gt 100 ] && mail -s warning root < /var/err/log

chmod +x 4.sh

crontab -e

* * * * * /root/4.sh

示例:判断电脑apache启动了没有,没有启动就启动它

#!/bin/bash

netstat -ntulp |grep httpd &>/dev/null

[ $? -ne 0 ] && systemctl start httpd

 

[ -d /abc ]是否存在目录      [ ! -d /abc ]是否不存在目录

[ -z ]是否为空               [ ! -z ]是否为非空

示例:判断/media/是否有abc目录,如果没有自动创建并touch一个文件a.txt,有则touch一个文件a.txt

#!/bin/bash

dir=”/media/abc”

 [ -d $dir ] || mkdir $dir  

 touch $dir/a.txt 

或 [ ! -d $dir ] && mkdir $dir 

 touch $dir/a.txt 

组合多个条件 

主要用法:命令1 操作符 命令2 ……

  [条件1] 操作符 [条件2]……

逻辑分隔操作

操作符

含义

示例

逻辑与

&&

多个判断条件必须同时成立,结果才为真。

[ $UID == root ] && [ -e /etc/passwd ]

[ -e "/studir2" ] && echo "ok" 

逻辑或

||

多个判断条件时某一个判断条件成立,结果为真

检查变量X的值是否小于10或者小于30:[[ $X -lt 10 || $X -lt 30 ]] && echo "YES"

逻辑非

!

取反

test -z ""         test ! -z ""

echo $?

# A&&B       仅A命令成功,才执行B命令

# A||B      仅A不成功,才执行B命令

# A;B;C      执行A,执行B,执行C,没有逻辑关系

多个条件组合时,可以使用 [[ .. ]] 界定:[[ $X -gt 10 && $X -lt 30 ]] && echo "YES"

你可能感兴趣的:(Linux命令,脚本)