Linux基础学习笔记6-SHELL编程

 

编程基础

程序:指令+数据
程序编程风格:
    过程式:以指令为中心,数据服务于指令
    对象式:以数据为中心,指令服务于数据
shell程序:提供了编程能力,解释执行
编程基本概念:
    顺序执行;循环执行;选择执行
shell编程:过程式、解释执行
    编程语言的基本结构
        各种系统命令的组合
        数据存储:变量、数组
        表达式:a+b
        语句:if

shell脚本基础

shell脚本:包含一些命令或声明,并符合一定格式的文本文件
格式要求:首行shebang机制
    #! /bin/bash
    #! /usr/bin/python
    #! /usr/bin/perl
shell脚本的用途有:
    自动化常用命令
    执行系统管理和故障排序
    创建简单的应用程序
    处理文本或文件

创建shell脚本

第一步:使用文本编辑器来创建文本文件
    第一行必须使用包括shell声明序列:#
        #!/bin/bash
        添加注释
        注释以#开头
    第二步:运行脚本
        给予执行权限,在命令行上指定脚本作为解释器程序的参数运行
        直接运行解释器,将脚本作为解释器程序的参数运行

脚本规范:
脚本代码开头约定
  1.第一行一般为调用使用的语言
  2.程序名,避免更改文件名为无法找到正确的文件
  3.版本号
  4.更改后的时间
  5.作者相关信息
  6.该程序的作用,及注意事项
  7.最后是各版本的更新及简要说明
脚本的基本结构:
  #!SHEBANG
  CONFIGURATION_VARIABLES
  FUNCTION_DEFINITIONS
  MAIN_CODE

shell脚本示例:

脚本调试

检测脚本中语法错误 
    bash -n /path/to/some_script
调试执行
    bash -x /path/to/some_script

变量

变量:命名的内存空间
    数据存储方式:
    字符:
    数值:整型、浮点型
变量:变量类型
    作用:1.数据存储格式
         2.参与的运算
         3.表示的数据范围

强类型:变量不经过强制转换,它永远是这个数据类型,不允许隐式的类型转换。一般定义变量时必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误。如java,c#
弱类型:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用。如bash不支持浮点数,php
变量命名规则:
  1.不能使用程序中的保留字:例如if,for
  2.只能使用数字、字母及下划线,且不能以数字开头
  3.见名知义
  4.统一命名规则:驼峰命名法

bash中变量的变种

根据变量的生效范围等标准划分下面变量类型:
  局部变量:生效范围为当前shell进程;对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效
  环境(全局)变量:生效范围为当前shell进程及其子进程(利用export声明即为环境变量)
  本地变量:生效范围为当前shell进程中某代码片段,通常指函数
  位置变量:$1,$2,...来表示,用于让脚本在脚本代码中调用命令行传递给它的参数
  特殊变量:$?,$0(代表脚本名称),$*(代表所有参数),$@(代表所有参数),$#(代表参数数量),$$
注意:#@与#*的区别在于#*会将所有位置参数当成一个整体
echo $$:查看当前shell运行的系统编号
pstree -p:查看当前系统运行的shell树状结构
scp命令:可以跨网络将本机数据发送到另外一台机器上

局部变量
变量赋值:name='value'
可以使用引用value:
  (1)可以是直接字串;name="root"
  (2)变量引用:name="$USER"
  (3)命令引用:name='COMMAND' name=$(COMMAND)
变量引用:${name} $name
  "":弱引用,其中的变量引用会被替换为变量值
  '':强引用,其中的变量引用不会被替换为变量值,而保持源字符串
显示已定义的所有变量:set
删除变量:unset name

环境变量
变量声明、赋值
  export name=VALUE
  declare -x name=VALUE
变量引用:$name,${name}
显示所有环境变量:
  env
  printenv  
  export  
  declare -x
删除变量 unset name

bash内建的环境变量:PATH,SHELL,USER,UID,HOME,PWD,SHLVL,MAIL,HISTSIZE,- 等等。
  

只读和位置变量

只读变量:只能声明,但不能修改和删除
    声明只读变量:readonly name    
                        declare -r name
    查看只读变量:readonly -p
位置变量:在脚本代码中调用通过命令行传递给脚本的参数
    $1,$2,...:对应第一,第二等参数,shift[n]换位置
    $0:命令本身
    $*:传递给脚本的所有参数。全部参数合为一个字符串
    $@:传递给脚本的所有参数,每个参数为独立字符串
    $#:传递给脚本的参数个数
            $@ $* 只在被双引号包起来的时候才会有差异
    set -- 清空所有位置变量  

退出状态

进程使用退出状态来报告成功或失败
    0代表成功,1-255代表失败
    $?变量保存最近的命令退出状态
例如:
        print -c1 -W1 hostdown &> /dev/null
        echo $?
退出状态码
bash自定义退出状态码
exit[n]:自定义退出状态码
注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字;
如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

 算术运算

bash中的算术运算:help let
    +,-,*,/,%取模(取余),**(乘方)
    实现算术运算:
    (1)let var=算术表达式
    (2)var=$[算术表达式]
    (3)var=$((算术表达式))
    (4)var=$(expr arg1 arg2 ...)
    (5)declare -i var =数值
    (6)echo '算术表达式' | bc
乘法符号在有些场景中需要转义,如*
bash有内建的随机数生成器:$RANDOM(0-32767)
    echo $[$RANDOM%50]:0-49之间随机数

赋值:+=,-=,==,/=,%=
let var OPER value:let count+=3
自增自减:let var +=1 ;let var++ ;let var -=1; let var--;

逻辑运算

 

 条件测试

判断某需求是否满足,需要由测试机制来实现
    专用的测试表达式需要由测试命令辅助完成测试过程
评估布尔声明,以便用在条件性执行中
    若真,则返回0
    若假,则返回1
测试命令:
    test EXPRESSION
    [EXPRESSION]
    [[EXPRESSION]](这种情况适用于带有正则表达式的情况)
注意:EXPRESSION前后必须有空白字符

条件性的执行操作符
根据退出状态而定,命令可以有条件地运行
  && 代表条件性的AND THEN
  || 代表条件性的OR ELSE
例如:
  grep -q no_such_user /etc/passwd || echo 'No such user'  
  输出:No such user
  ping -c1 -W2 station &> /dev/null > && echo "Station1 is up" > ||(echo 'Station1 is unreachable';exit1)
  输出:Station1 is up

test命令(内部命令,查看帮助:help test)
  长格式的例子:
    test "$A" == "$B" && echo "Strings are equal"
    test "$A" -eq "$B" && echo "Integers are equal"
  简写格式的例子:
    ["$A" == "$B"] && echo "Strings are equal"
    ["$A" -eq "$B"] && echo "Integers are equal"
 
bash的数值测试
-v VAR:变量VAR是否设置
数值测试:
  -gt  是否大于
  -ge  是否大于等于
  -eq  是否等于
  -ne  是否不等于
  -lt  是否小于
  -le  是否小于等于
bash的字符串测试
  ==  是否等于
  >  ascii码是否大于ascii码
  <  是否小于
  !=  是否不等于
  =~  左侧字符串是否能够被右侧的PATTERN所匹配(此表达式一般用于[[]]中;扩展的正则表达式)
  -z  "STRING"  字符串是否为空,空为真,不空为假
  -n  "STRING"  字符串是否不空,不空为真,空为假
注意:用于字符串比较时用到的操作数都应该使用引号

 bash的文件测试

存在性测试
  -a FILE:同-e
  -e FILE:文件存在性测试,存在为真,否则为假
存在性及类别测试
  -b FILE:是否存在且为设备文件
          

示例:[-f /etc/issue] && echo true

   [-d /etc/] && echo true

bash文件权限测试

文件权限测试:
    -r FILE:是否存在且可读
    -w FILE:是否存在且可写
    -x FILE:是否存在且可执行
文件特殊权限测试:
    -u FILE:是否存在且拥有suid权限
    -g FILE:是否存在且拥有sgid权限
    -k FILE:是否存在且拥有sticky权限

bash的文件属性测试

文件大小测试
    -s FILE:是否存在且非空
文件是否打开:
    -t fd:fd文件描述是否在某终端已经打开
    -N FILE:文件自从上一次被读取之后是否被修改过
    -O FILE:当前有效用户是否为文件属主
    -G FILE:当前有效用户是否为文件属组
双目测试:
  FILE1 -ef FILE2:FILE1是否是FILE2的硬链接
  FILE1 -nt FILE2:FILE1是否新于FILE2(mtime)
  FILE1 -ot FILE2:FILE1是否旧于FILE2  

bash的组合测试条件

第一种方式:
    COMMAND1 && COMMAND2
    COMMADN1 || COMMADN2
    !COMMAND
    如:[[ -r FILE ]] && [[ -w FILE ]]
第二种方式:
    EXPRESSION1 -a EXPRESSION2
    EXPRESSION1 -o EXPRESSION2
    !EXPRESSION
    必须使用测试命令进行
示例:[ -z "$HOSTNAME" -o "$HOSTNAME"=="localhost.localdomain"] && hostname www.ccsu.com [ -f /bin/cat -a -x /bin/cat] && cat /etc/fstab  

使用read命令来接收输入

使用read来把输入值分配给一个或多个shell变量    
    -p 指定要显示的提示
    -s 静默输入,一般用于密码
    -n N 指定输入的字符串长度
    -d '字符'输入结束符
    -t N TIMEOUT为N秒
    read 从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量
    read -p "Enter a filename:" FILE

流程控制 

过程式编程语言:
    顺序执行
    选择执行
    循环执行

条件选择if语句

if语句示例:
    read -p"please onput your age:" age
  [[ "$age" =~ [0-9]+$ ]] ||{echo your age is false;exit10;}
    if [ "$age" -gt 0 -a  "$age" -le 18];then
            echo "you are young"
    elif[ "$age" -gt 18-a  "$age" -le 50];then
            echo woek hard
    elif ["$age" -gt 50 -a  "$age" -le 80];then
            echo "very ok"
    else
            echo "you do not come from earth"
    fi

条件判断:case语句

case语句示例:
    read -p"Do you agree?tes or no:"anwser
    case $answer in
    [Yy]|([Yy][Ee][Ss])
            echo your answer is yes
            ;;
    [Nn]|[Nn][Oo])
            echo your answer is no
            ;;
    *)
            echo your answer is false
            ;;
    esac

循环

循环执行
    将某段代码重复运行多次
    重复运行多少次
        循环次数事先已知
        循环次数事先未知
    有进入条件和退出条件
for;while;until

 for循环

 

for循环示例1
    显示root下所有的txt格式文件:
    for name in `ls /root/*.txt`;do echo "$name";done 
for循环示例2
  求1-100之间的奇数和
  sum=0;for number in `seq 1 2 100`;do let sum+=number;done;echo "sum is $sum"

while循环

while循环示例1
  求1-100之间的奇数和
  sum=0;i=1;while ["$i" -le 100];do let sum+=i;let i+=2;echo "sum is $sum" 

until循环

循环控制语句continue

循环控制语句break

for循环的特殊用法:

for循环的特殊用法示例:
    求1-100之间的奇数和
    for((sum=0,i=1;i<100;i+=2));do let sum+=i;done;echo "sum is $sum"

函数介绍

函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程
它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分
函数和shell程序比较相似,区别在于:
    shell程序在子shell中运行
    而shell函数在当前shell中运行。因此在当前shell中,函数可以对shell中变量进行修改

定义函数

cat /etc/init.d/functions 查看系统自定义的函数

 函数使用

函数返回值

函数返回值示例:
checkip(){
  [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]  && echo "This is a IP" || {echo "This is not IP" ;return 10;}
}
注意:返回值返回给了调用者  

交互式环境下定义和使用函数

在脚本中定义及使用函数

定义一个ip检查函数
checkip(){
  [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]  && echo "This is a IP" || echo "This is not IP"
}
调用函数
checkip
删除函数
unset checkip 

使用函数文件

创建函数文件

 

载入函数

检查载入函数

执行shell函数

删除shell函数

函数参数:

函数变量

局部变量示例

函数递归示例

函数递归示例

fork炸弹

数组

数组赋值

引用数组

数组数据处理

数组示例1

数组示例2

posted @ 2019-03-21 13:35  小鲨鱼~  阅读(182)  评论(0)    收藏  举报