zoukankan      html  css  js  c++  java
  • shell的基础

    学习shell编程的基础:

    shell脚本语言是实现linux系统自动化管理的重要且必要的工具,因此需要熟练掌握shell脚本语言,可以提升工作效率解决工作中重复的劳动。

    学好shell编程并实现通过shell自动化管理系统基础必备:

    1. vi/vim编辑器的熟练使用,ssh终端及.vimrc的设备等等需要搞熟练 2. 命令基础:liunx150个常用命令的熟练使用,这个见前文的课程讲解及课后作业 3. 常见linux网络服务部署排错 如:crond nfs rsync inotify lanmp sersync ssh等 4. linux正则表达式以及三剑客要熟练

    shell脚本简介:

    shell是一个命令解释器,操作在系统的 外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕返回给用户。这种对话方式可以使交互的方式(从键盘输入,立即得到shell的回应),或非交互脚本方式

    img

    什么是shell脚本:

    当liunx命令或语句不在命令行执行(严格说,命令行也是shell),而是通过一个程序文件执行时,该程序就被称为shell脚本或shel程序 shell程序类似于DOS系统下的批处理程序(.bat)

    用户可以在shell脚本中敲入一系列的命令及命令语句组合。这些命令、变量和流程控制语句等有机的结合起来就形成了一个功能强大的 shell脚本

    ===========================================================================

    shell脚本简单举例说明:

    范例1:清除/var/log下的messages日志文件的简单命令脚本 cd /var/log cat /dev/null >messages echo "logs cleaned up"

    以上脚本信息的不完善之处: 1. 上面脚本,如果不是root就无法执行清理日志 2. 没有任何的流程控制语句,就是顺序操作,没有成功判断和逻辑性

    范例2:包含命令 变量和流程控制语句的清除/var/log下messages日志文件的shell脚本

    !/bin/bash

    清除日志脚本,版本2

    LOG_DIR=/var/log
    ROOT_UID=0                     表示$UID为0的时候,用户才具有root用户的权限

    要使用root用户来运行

    if [ "(UID" -ne ")ROOT_UID" ]
    then
       ehco "Must be root to run this scripts"
       exit 1 fi

    进入到日志目录下,如果执行不正确便提示不能改变,>&2表示错误输出,并退出 cd $LOG_DIR || {

    echo "Cannot change to necessary directory." >&2
       exit 1
    }

    以上两个条件满足,及可执行下面的操作

    cat /dev/null >messages && echo "log cleaned up." exit 0

    推出之前返回0表示成功,返回1表示失败 ps: 清空日志的3中方式

    1. echo >test.log

    2. test.log

    3. cat /dev/null >test.log

    ===========================================================================

    dmesg - 打印或控制内核buffer命令,对系统以外出现故障的检查命令

    要对命令进行总结(命令已总结)

    ===========================================================================

    shell脚本在运维工作中的作用地位:

    shell脚本很擅长处理纯文本类型的数据,liunx中几乎所有的配置文件,日志文件等都是纯文本类型的文件可以利用shell在linux系统中发挥巨大作用

    shell脚本语言的种类:(主要分为两大类shell)

    1. bourne shell (包括sh,ksh,bash)

    ​ bourne shell(sh) kor n shell(ksh) bourne again shell (bash) posix shell(sh)

    2. C shell(包括csh and tcsh) C shell(csh)

    ​ TENEX/TOPS C shell(tcsh) ps:以上这些shell可以再linux中查询到,cat /etc/shell shell脚本语言是弱类型语言,常用bash shell

    其它运维人员常用的脚本语言种类:

    PHP: php是网页程序,也是脚本语言,专注于web页面开发。eg:dedecms discuz 也可以处理系统日志,配置文件等 perl: perl脚本语言,比shell强大的多,语法灵活 复杂 实现方式多 不易读 团队协作困难 python: 可以做脚本开发,也可以实现web开发,软件开发。中等以上公司都要求会python 复杂的日志分析,逻辑处理 python可以开发软件

    python课程参考:oldboy.blog.51cto.com/2561410/1123127

    shell与3P语言的区别和优势

    shell优势在于处理操作系统底层的业务,因为有大量的系统命令为它做支撑,2000多个命令都是shell编程的有利支撑特别是grep awk sed等

    php python优势在于开发运维工具,web界面的管理工具,以及web业务的开发等,处理一键软件装,优化,报警脚本,常规的业务应用等PHP/python也是能共做到的,但是开发效率和复杂度比用shell就差很多了

    业务需求和脚本语言选择不当的网友例子:增加了复杂度和难度

    wangwei007.blog.51cto.com/68019/903352

    考试题:Centos linux系统默认的shell是---bash(查看方式 echo $shell)

    ===========================================================================

    shell脚本的建立:(简单 易用 高效)

    在linux系统中,shell脚本通常是在编辑器(如vi/vim)中编写由unix/linux命令,bash shell命令、程序结构控制语句和注释等组成(4个部分组成)脚本开头(第一行)

    规范的shell脚本的第一行会指出由哪个程序(解释器)来执行脚本中的内容,在linux bash程序中一般为

    #!/bin/bash 或 #!/bin/sh () 其中开头#!又称为幻数,在执行bash脚本的时候,内核会根据#!后的解释器来确定该用哪个程序解释脚本中的内容这一行必须在每个脚本顶端的第一行,如果不是第一行则为脚本注释行 如果不写这行,系统默认的shell是什么,就用什么shell解释,一般系统脚本都是#!/bin/bash(标准写法) sh和bash的区别: sh是bash的软链接 bash --version 查看bash的版本

    其它语言的开头标识内容:

    !/bin/sh

    !/bin/bash

    !/usr/bin/awk

    !/bin/sed

    !/usr/bin/tcl

    !/usr/bin/expect

    !/usr/bin/perl

    !/usr/bin/env python

    脚本注释:****在shell脚本中,跟在#后面的内容表示注释,用来对脚本进行注释说明,注释部分不会被当做程序执行。注释可以自成一行,也可以跟在脚本命令后面与命令在同一行。

    尽量养成为所开发的shell脚本书写注释的习惯 shell脚本的执行: shell脚本以非交互的方式(文件方式)运行时,会先查找环境变量ENV,该变量指定了一个环境文件(通常是.bashrc .bash_profile /etc/bashrc /etc/profile等),然后从该环境变量文件开始执行,当读取了ENV文件后,shell才开始执行shell脚本中的内容定时任务中写脚本时,系统环境变量在脚本中重新定义 shell脚本的执行通常可以采用以下3中方式 ①bash scripts-name 或 sh scripts-name(推荐使用) 当脚本文件本身没有可执行权限(即文件x位为-号)时常使用的方法,这里推荐用bash执行,或者文件开头没有指定解释。
    ②path/scripts-name 或 ./scripts-name(当前路径下执行脚本) 需要先将脚本文件的权限改为可执行(即文件加x位),具体方法:chomd u+x scripts-name 或chmod 755 scripts-name 然后通过脚本路径就可以直接执行脚本了。
    ③source scripts-name 或 . scripts-name(可以把脚本中变量函数带入到当前的shell) 依次执行指定shell脚本文件中的所有语句。这些语句将作为当前父shell脚本进程的一部分运行。 因此可以将自身脚本中的变量的值或函数等的返回值传递到当前的父shell脚本中使用。

    举例说明:
    cat test.sh user=whoami sh test.sh echo $user

    返回结果为:空

    说明:因为sh执行的脚本不会保存在系统环境变量中,echo $user调用的是系统环境变量,因此为空

    ​ 修改方式可以用source或点来执行

    ④sh<scripts-name 或 cat scripts -name |sh(同样适合bash)

    shell脚本开发基本规范及习惯

    1. 开头指定脚本解释器

    ​ #!/bin/sh 或 #!/bin/bash

    2. 开头加版本版权等信息

    uploading-image-92188.png

    提示:可配置vim编辑文件时自动加上以上信息,方法是修改~/.vimrc配置文件

    3. 脚本中不用中文注释

    ​ 尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰

    4. 脚本以.sh为扩展名

    5. 代码书写优秀习惯

    1. 成对内容的一次写出来,防止遗漏
    2. 中括号两端要有空格,书写时即可留出空格,然后退格书写内容
    3. 流程控制语句一次书写完,再添加内容

    6. 通过缩进让代码易读

    =========================================================================== shell变量基础及深入什么是变量:

    方程式x=1 y=x+1,即x y为变量,1和x+1是变量的内容 变量就是用一个固定的字符串(也可能是字符数字等的组合),替代更多更复杂的内容,这个内容里可能还包含变量和路径,字符创等其它的内容。使用变量的 大好处就是方便,当然很多时候在编程中使用变量也是必须的,否则无法完成开发工作 变量的类型: 分为两类:环境变量(全局变量)和局部变量环境变量也称为全局变量,可以在创建他们的shell及其派生出来的任意子进程shell中使用。 局部变量只能在创建他们的shell函数或脚本中使用 还有一些变量是用户创建的,其它的测试专用shell变量

    ===========================================================================

    1. 环境变量:(env检查系统的环境变量)用于定义shell的运行环境,保证shell命令的正确执行,shell通过环境变量来确定登录用户名,命令路径、终端类型、登录目录等所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、shell脚本和各类应用等。

    环境变量可以再命令行中设置,但用户退出是这些变量值也会消失,因此 好在用户家目录下bash_profile文件中或全局配 置/etc/bashrc /etc/profile文件或者/etc/profile.d/中定义。将环境变量放入profile文件中,每次用户登录时这些变量值都将被初始化。 传统上,所有环境变量均为大写。环境变量应用于用户进程前,都应用export命令导出 自定义环境变量(全局变量)如果想设置环境变量,就要在给变量赋值之后或设置变量时使用export命令。带-x选项的declare内置命令也可完成同样的功能 (输出变量时不要在变量名前面加$)
    ①export 变量名=value
    ②变量名=value;export 变量名
    ③declare -x 变量名=value
    显示与取消环境变量:
    通过echo命令打印1换将变量: $HOME
    用户登录时进入的目录 $UID 当前用户的UID(用户标识)
    相当于id-u $PWD 当前工作目录的绝对路径名 $SHELL
    当前shell $USER 当前用户 用unset消除本地变量和环境变量
    unset 变量名 即取消环境变量设置

    ===========================================================================

    2 局部变量

    定义本地变量

    本地变量在用户当前的shell生存期的脚本中使用。
    例如:本地变量OLDBOY取值为ett098,这个值只在用户当前shell生存期有意思
    如果在shell中其启动另一个进程或退出,本地变量OLDBOY值将无效
    普通字符串变量定义:
    变量名=value
    变量名='value'
    变量名="value"
    命令变量: 变量名=`` 变量名=$()
    ps:shell中变量名的要求,一般是字母,数字,下划线组成。字母开头
    连续普通字符串,定义变量,内容是什么,变量打印输出就是什么

    提示: > 第一种定义a变量的方式是直接定义变量内容,内容一般为简单连续的数字,字符串路径名等 > 第二种定义b变量的方式是通过单引号定义变量。
    这个方式的特点是:输出变量时引号里是什么就输出什么,即使内容中有变量也会把变量名原样输出。 此法适合定义显示纯字符串 > 第三种定义C变量方式是通过双引号定义变量。
    这个方式的特点是:输出变量时引号里的变量及命令会经过解析后输出该变量内容,而不是吧引号中变量原样输出,
    适合于字符创中附带变量的内容的定义

    习惯:数字不加引号,其它默认3加双引号

    有关单引号 双引号与不加引号的简要说明

    名称 解释
    单引号 可以说是所见即所得;即将单引号内的所有内容都原样输出,或者描述为单引号里面看到的是什么就会输出什么
    双引号 把双引号内的所有内容都输出出来;如果内容中有命令(要反引下)、变量特殊转义符等,会先把变量,命令解析出结果,然后再输出 终内容来
    无引号 把内容输出出来,会将含有空格的字符串视为一个整体输出,如果内容中有命令。变量等,会先把变量、命令解析出结果,然后在输出 终内容来,如果字符串中带有空格等特殊字符,则不能完整的输出,需要改加双引号,一般连续的字符串,数字。路径等可以不加任何引号,不过无引号的情况 好用双引号替代之。
    反引号 一般用于引用命令,执行的时候命令会被执行
    提示 可能对于某些语言不适合,例如awk内部就有特殊

    ps:脚本中普通字符串尽量双引号,单纯数字可以不加引号,希望原样输出加单引号,引用命令用反引号

    ===========================================================================

    扩展题参考:

    这个例子更特殊了一点,有关awk调用shell变量可以参考的博文:9种shell解答问题 oldboy.blog.51cto.com/2561410/760192

    ===========================================================================

    自定义变量的建议:

    1. 纯数字(不带空格),定义方式可以不加引号(单或双)

    2. 没特殊情况,字符串一般用双引号定义,特别是多个字符串中间有空格时。

    3. 变量内容需要原样输出时,要用单引号

    变量的命名规范:

    1. 变量命名要统一,使用全部大写字符,语义要清晰,能够正确表达变量内容的含义,过长的英文单词可采用前几个字符代替。

    多个单词连接使用_下划线连接,引用时, 好以({}加大括号或“){}”外面加双引号方式引用变量

    2. 避免无含义字符或数字

    3. 全局变量和局部变量命名

    a 脚本中的全局变量定义,在变量使用时,使用{}将变量括起或“${}”

    b 脚本中局部变量定义:存在于脚本函数(function)中的变量称为局部变量,要以local方式进行声明,使之只在本函数作用域内

    有效,防止变量在函数中的命名与变量外部程序中变量重名造成程序异常

    4. 变量合并,某些变量或配置项要组合起来才有意义,如文件的路径和文件名称,建议将要组合的变量合并到一起赋值给一个新的

    变量,即方便之后的调用,也为以后进行修改提供了方便

    5. 变量定义总结:多学习模仿操作系统自带的函数库(/etc/init.d/functions)函数库脚本的定义思路

    **把命令作为变量定义方法:
    **变量名=ls ç反引号

    变量名=((ls) ZIP=`tar zcvf etc_)(date +%F).tar.gz /etc/hosts LL=ls -lrt RM=$(rm -f etc_2015-08-11.tar.gz) ZIP=$(tar zcvf etc_date +%F`.tar.gz /etc/hosts)

    ps:小结****普通变量

    a=1 连续的数字 a="/etc/rc.local (USER" a=')USER' 原样输出

    命令内容定义

    变量名=ls ç反引号变量名=$(ls) 变量名及变量内容定义小结:
    1. **变量名只能为字母,数字 下划线 字母开头 **
    2. **规范的变量名写法定义 a OldboyAge=1 每个单词的首字母大写 b oldboy_age=1 **
    单词之间用“_” c oldboyAgeSex=1 驼峰语法,单个单词的首字母小写,其余单词首字母大写 **
    3. **=号的知识 a=1中的,等号是赋值的意思,比较是不是相等,为“==” **

    4. 打印变量,变量名的前接$符号,变量名后面紧接着字符的时候,要用大括号括起来

    5. 注意变量内容引用的方法,一般用双引号,简单连续字符串可以不加引号,希望原样输出,使用单引号

    6. 变量内容是命令,要用反引号``或者$()把变量括起来使用

    ===========================================================================

    shell特殊变量****:

    重点需要掌握:$? $n $# $0

    1. 位置变量:

    $0 获取当前执行的shell脚本的文件名,如果执行脚本带路径,那么就包含脚本路径

    [root@moban scripts]# cat test01.sh
    echo $0
    [root@moban scripts]# sh test01.sh test01.sh
    [root@moban scripts]# sh /server/scripts/test01.sh
    /server/scripts/test01.sh
    说明:参数变量应用在shell脚本需要调用脚本的文件名及路径时
    [root@moban scripts]# cat test01.sh
    dirname $0                       指定显示全路径中的目录路径信息
    basename $0                    指定显示全路径中的文件名称信息
    [root@moban scripts]# sh /server/scripts/test01.sh
    /server/scripts
    test01.sh

    说明:两个控制路径及文件信息显示命令

    (n 获取当前执行的shell脚本的第n个参数值,n=1..9 ,当 n 为0时表示脚本的文件名及脚本路径,如果n大于9,用大括号括起来){10},参数以空格隔开。

    [root@moban scripts]# echo 'echo' '$'{1..15} >test02.sh
    [root@moban scripts]# cat test02.sh
    echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
    [root@moban scripts]# sh test02.sh {a..z}
    a b c d e f g h i a0 a1 a2 a3 a4 a5
    [root@moban scripts]# cat test02.sh
    echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ({15} [root@moban scripts]# sh test02.sh {a..z} a b c d e f g h i j k l m n o 说明:利用)n进行传参,多个参数用空格分割,双引号中多个参数表示一个 大于9的传参要用${},避免金庸新著问题

    $# 表示取传参的个数,获取当前shell脚本命令行中参数的总个数

    [root@moban scripts]# cat test03.sh echo $1 (2 echo )# [root@moban scripts]# sh test03.sh 1 2 1 2 2
    [root@moban scripts]# sh test03.sh 1 2 3 1 2 3
    说明:表示传参的个数,不管有没有定义传参的数量,只要输入了多个参数,都会进行统计传参总数 应用于控制用户传参的个数

    [root@MySQL 01]# cat t1.sh
    条件判断语句,判断传参数是否正确

    !/bin/sh

    [ $# -ne 2 ] && { echo "$0 ARG1 ARG2" exit 1 }
    echo oldboy function judge_arg_num(){
    正式函数if语句,判断传参数是否正确
    if [ $# -ne 2 ] then ;
    echo "Usage: $0 {}" exit 2 }
    fi

    说明:应用判断传参信息的,实际shell函数脚本

    $* 获取当前shell的所有参数,会把将所有参数视为一个字符串传给脚本 “$1$2$3”

    $@ 会接收所有的参数 "$1" "$2" "$3" 但多个参数分开显示。这是将参数传递给其它程序的最佳方式,

    因为会保留所有内嵌在每个参数里的任何空白

    [root@moban scripts]# set -- "I am" handsome oldboy             传入三个字符串参数
    [root@moban scripts]# echo (#                                                     输出现在有的传参参数数量 3 [root@moban scripts]# for i in ")*";do echo (i;done I am handsome oldboy 说明:三个字符串参数,作为一个参数一行输出 [root@moban scripts]# for i in ")@";do echo $i;done I am handsome
    oldboy
    说明:三个字符串参数,作为三个参数逐行输出
    [root@moban scripts]# for i;do echo (i;done        I am handsome oldboy 说明:循环语句变量后不加参数,变量i等价于)@
    PS:(*和)@区别仅在于加双引号的时候,即"(*"与")@"

    2. 进程的状态变量:

    $? 表示命令的返回值,获取执行上一个指令的返回值(0为成功,非0为失败)常用变量返回值参考资料:

    0 表示运行成功
    2 权限阻止
    1~125 表示运行失败,脚本命令,系统命令错误或参数传递错误
    126 找到该命令了,但无法执行
    127 未找到要运行的命令
    >128 命令被系统强制结束

    ps:脚本中调用,一般exit0,脚本返回值给(? 函数中return0,函数返回值给)?

    企业场景返回值的用法:

    1. 判断命令或脚本是否执行成功

    2. 通过在脚本调用exit数字,则脚本返回这个数字给(? 如果是函数里return数字,则函数返回值给)?

    $$ 当前shell脚本的进程号PID的获取

    [root@moban scripts]# cat test04.sh echo $$ >/tmp/a.pid sleep 300
    [root@moban scripts]# sh test04.sh &
    [1] 24349
    [root@moban scripts]# ps -ef|grep test04.sh                                    确认进程中是否有后台运行的脚本
    root     24349 23586  0 04:02 pts/0    00:00:00 sh test04.sh root     24352 23586  0 04:04 pts/0    00:00:00 grep test04.sh
    [root@moban scripts]# cat /tmp/a.pid                                               查看指定文件中是否生成进程号
    24349
    [root@moban scripts]# kill -USR2 cat /tmp/a.pid                           利用参数优雅杀死指定进程
    [root@moban scripts]# ps -ef|grep test04.sh
    root     24363 23586  0 04:05 pts/0    00:00:00 grep test04.sh

    说明:用于获取执行脚本程序的进程号,生成进程号文件,便于编写脚本停止脚本程序

    #!/bin/sh
    pidpath=/tmp/a.pid
    if [ -f "$pidpath" ] ;then
    kill -USR2 cat $pidpath
    rm -f $pidpath fi echo $$ >$pidpath sleep 300
    fi

    用途:当系统中只能有某个脚本同时只能运行一个进程的时候,从而避免一个脚本启动多个进程

    $! 执行上一个执行的PID

    $_ 在此之前执行的命令或脚本的 后一个参数

    其他:linux下set和eval的使用小案例精彩解答(特殊位置变量用法)

    http://oldboy.blog.51cto.com/2561410/1175971

    PS: shift命令-移动位置变量,用于将传参的参数依次向前移动位置,原有的$2变为$1 $3变为$2 $1传参参数消失

    ===========================================================================

    bash内部变量命令: man bash可以查看bash命令信息

    bash命令解释套装程序包含了一些内部命令。有些内部命令在目录列表时是看不见的,由shell本身提供。常用的命令有:

    alias bg cd continue declare echo eval exec exit export fg getopts help history jobs kill let local logout printf pwd read return set shift source test times trap type typeset ulimit umask unalias unset

    ①echo基本的输出命令

    echo - Display message on screen
    命令格式:echo args 可以是字符串和变量组合
    功能:将echo命令后面args指定的字符串及变量等显示到标准输出

    ②eval

    ​命令格式: eval args
    功能:当shell程序执行到eval语句时,shell读入参数args,并将它们组合成一个新的命令,然后执行

    ③exec

    ​命令格式:exec命令参数
    功能:当shell执行到exec语句时,不会去创建新的子进程,而是转去执行指定的命令,当指定的命令执行完时,该进程(也就是 初的shell)就终止了,所以shell程序中exec后面的语句将不再被执行

    ④export

    ​命令格式:
    export 变量名 或:export 变量名=变量值
    功能:shell可以用export把它的变量向下带入子shell,从而让子进程继承父进程中的环境变量。 但子shell不能用export把它的变量向上带入父shell
    PS:不带任何变量名的export语句将显示出当前所有的export变量

    作业总结:echo eval exec export read shift exit----内置命令总结

    ===========================================================================

    变量子串的常用操作(了解即可)相关资料的获取 man bash中获取

    1. ({#string} ---返回)string的长度

    [root@moban scripts]# OLDBOY="I am oldboy"
    [root@moban scripts]# echo $OLDBOY I am oldboy
    [root@moban scripts]# echo ${#OLDBOY} 变量前加#号,直接算出输出的字符串长度 11

    其它去字符串长度方法:

    expr length "$OLDBOY" echo $OLDBOY|wc -L wc命令-L参数也是取所有字符串数量

    实际案例应用脚本

    I am oldboy linux,welcome to our training. #取小于6的字符串
    for n in I am oldboy linux welcome to our training. do
    if [ ${#n} -lt 6 ] ;then
    echo $n
    fi done
    说明:利用变量字符串功能,控制取出相应字符串数量的字符

    2. ({#string:position} ---在)string中,从位置$position之后开始提取子串

    echo $(##:2:6) 从第2个字符开始,不包含第2个,输出的长度,不指定长度表示到结尾

    [root@MySQL 01]# echo $OLDBOY I am oldboy
    [root@MySQL 01]# echo ${OLDBOY:2} am oldboy
    [root@MySQL 01]# echo ${OLDBOY:3} m oldboy

    3. ({#string:position:length} ---在)string中,从位置(position之后开始提取长度为)length的子串

    echo $(##:2:6) 从第2个字符开始,不包含第2个,输出的长度,不指定长度表示到结尾

    [root@MySQL 01]# echo $OLDBOY
    I am oldboy
    [root@MySQL 01]# echo ${OLDBOY:2:6} am old
    [root@MySQL 01]# echo ${OLDBOY:2:2}
    am
    [root@MySQL 01]# echo ${OLDBOY:3:2}
    m
    [root@MySQL 01]# echo ${OLDBOY:3:3}
    m o
    说明:类似于cut -c命令
    [root@moban scripts]# echo ${OLDBOY}|cut -c 1-4
    I am
    [root@moban scripts]# echo ${OLDBOY}|cut -c 3-4
    am

    4. ({string#substring} ---从变量)string开头开始删除短匹配$substring子串

    [root@MySQL 01]# OLDBOY=abcABC123ABCabc [root@MySQL 01]# echo ${OLDBOY} abcABC123ABCabc

    [root@MySQL 01]# echo ${OLDBOY#a*C} 删除a到C的 短部分,即abcABC

    123ABCabc

    [root@MySQL 01]# echo ${OLDBOY#a*c} 删除a到c的 短部分,即abc

    ABC123ABCabc

    说明:删除#后面 短匹配的部分,即从头开始找,找到即匹配,而非贪婪匹配模式

    5. ({string##substring} ---从变量)string开头开始删除长匹配$substring子串

    [root@MySQL 01]# OLDBOY=abcABC123ABCabc [root@MySQL 01]# echo ${OLDBOY} abcABC123ABCabc

    [root@MySQL 01]# echo ${OLDBOY##a*c} 删除a到c的 长部分,即abcABC123ABCabc
    [root@MySQL 01]# echo ${OLDBOY##a*C} 删除a到C的 长部分,即abcABC123ABC

    abc

    说明:删除##后面 长匹配的部分,即从头开始找,第一个字符找 先匹配的,后面字符贪婪匹配到 后

    6. ({string%substring} ---从变量)string结尾开始删除短匹配$substring子串

    [root@MySQL 01]# OLDBOY=abcABC123ABCabc [root@MySQL 01]# echo ${OLDBOY} abcABC123ABCabc

    [root@MySQL 01]# echo ${OLDBOY%a*C} 删除a到C 短部分,但从尾部开始匹配,即尾部没有a--C的字符串段

    abcABC123ABCabc

    [root@MySQL 01]# echo ${OLDBOY%a*c} 删除a到c 短部分,但从尾部开始匹配,即abc

    abcABC123ABC

    [root@MySQL 01]# echo ${OLDBOY%C*c} 删除C到c 短部分,但从尾部开始匹配,即Cabc

    abcABC123AB

    说明:删除%后面 短匹配的部分,即从尾部开始找,找到即匹配,而非贪婪匹配模式

    7. ({string%%substring} ---从变量)string结尾开始删除长匹配$substring子串

    [root@MySQL 01]# OLDBOY=abcABC123ABCabc [root@MySQL 01]# echo ${OLDBOY} abcABC123ABCabc

    [root@MySQL 01]# echo ${OLDBOY%%C*c} 删除C到c 长部分,但从尾部开始匹配,即C123ABCabc

    abcAB

    说明:删除%%后面长匹配的部分,即从尾部开始找,第一个字符找 先匹配的,后面字符贪婪匹配到后(从后向前)

    8. ({string/substring/replace} ---使用)replace,来代替第一个匹配的$substring

    [root@MySQL 01]# OLDBOY="I am oldboy oldboy oldgirl"

    [root@MySQL 01]# echo ${OLDBOY/oldboy/etiantian} 将第一个oldboy,即 先匹配的字符串进行替换

    I am etiantian oldboy oldgirl

    9. ${string/#substring/replace}

    ---如果(string前缀匹配)substring,就使用(replace来代替匹配)substring,第一个匹配的$substring

    [root@MySQL 01]# OLDBOY="I am oldboy oldboy oldgirl"

    [root@MySQL 01]# echo ${OLDBOY/#I*oldboy/etiantian} 将第I到oldboy的所有信息,即 先匹配的字符串进行替换

    etiantian oldgirl

    说明:搜索匹配的方式为贪婪匹配,I*oldboy等价于I am oldboy oldboy

    10. ${string/%substring/replace}

    ​ ---如果(string后缀匹配)substring,就使用(replace来代替匹配)substring,第一个匹配的$substring [root@MySQL 01]# OLDBOY="I am oldboy oldboy oldgirl" [root@MySQL 01]# echo ${OLDBOY/%rl/etiantian} 从字符串尾部搜索rl信息,替换为相应信息 I am oldboy oldboy oldgietiantian 说明:搜索匹配的方式为贪婪匹配(从后向前),rl等价oldgirl中的rl PS: 替换字符串应用案例参考:(批量修改扩展名) http://oldboy.blog.51cto.com/2561410/711342

    ===========================================================================

    变量的处理计算变量长度与其它不同方法的耗时对比:

    [root@MySQL 01]# chars=seq -s" " 100

    [root@MySQL 01]# echo $chars 创建char变量信息

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

    [root@MySQL 01]# echo ${#chars} 取变量数值统计字符数方法一
    291
    [root@MySQL 01]# echo ((expr length ")chars") 取变量数值统计字符数方法二
    291
    [root@MySQL 01]# echo ${chars}|wc –L 取变量数值统计字符数方法三

    291

    [root@MySQL 01]# time for i in ((seq 11111);do count=){#chars};done; real 0m0.512s user 0m0.503s sys 0m0.001s

    [root@MySQL 01]# time for i in $(seq 11111);do count=echo ${chars}|wc -L;done; real 0m21.410s user 0m0.869s sys 0m2.123s

    [root@MySQL 01]# time for i in ((seq 11111);do count=`echo expr length "){chars}"`;done real 0m5.702s user 0m0.391s sys 0m1.230s

    说明:三种取数据值统计字符的方法中,自身命令统计数值效率 高,管道方式统计效率 低

    PS:一般情况调用外部命令处理,与内置功能操作性能相差较大,shell编程中尽量用内置操作或函数完成

    ===========================================================================

    小结: #开头删除匹配 短

    ##开头删除匹配 长 %结尾删除匹配 短 %%结尾删除匹配 长

    变量的替换表:(了解即可)

    相关资料的获取 man bash中获取

    1. ((value:-word)==)(value-word)

    当变量未定义或者值为空时,返回值为word内容,否则返回变量的值。
    [root@moban scripts]# result=${test:-UNSET}
    [root@moban scripts]# echo $result                     result变量中未定义test变量时,显示备用信息UNSET
    UNSET
    [root@moban scripts]# test=1                         
    [root@moban scripts]# echo $test
    1
    [root@moban scripts]# echo (result                     test设置变量后也不能马上生效,需要重新定义变量result       UNSET [root@moban scripts]# result=){test:-UNSET}
    [root@moban scripts]# echo $result     
    1
    说明:用于一个变量为指定时,在备用变量位置输入信息,便于提示作用
               可以用来判断变量是否进行了定义

    2. $(value:?"word")

    [root@moban scripts]# value=1
    [root@moban scripts]# echo ${value:?"not defined"} 定义一个变量如果存在时,输出变量值 1 [root@moban scripts]# unset value
    [root@moban scripts]# echo ${value:?"not defined"} 定义变量不存在时,利用bash显示指定报错信息 -bash: value: not defined
    说明:用于捕捉由于变量未定义而导致的错误

    3. $(value:+word)

    [root@moban scripts]# r=${value:+1}               未定义value的数值,即没有变量值,无输出
    [root@moban scripts]# echo $r

    [root@moban scripts]# value=oldboy
    [root@moban scripts]# r=${value:+1} 
    [root@moban scripts]# echo $r                          定义了value的变量信息,即有变量值存储在,可以输出用于表示有变量存在
    1
    说明:此功能用于测试变量是否存在

    4. $(value:=word)

    ​ 若变量未定义或者值为空时,在返回word的值的同时将word赋值给value
    [root@moban scripts]# OLD=${value:=word}
    [root@moban scripts]# echo $OLD
    word
    [root@moban scripts]# echo $value value并没有赋值,但自动赋值了=后面的字符串
    word 说明:此种赋值方式,更适合在企业中脚本使用

    企业案例说明:删除脚本说明

    path=/tmp rm -fr $path
    说明:这些写删除脚本,在path上如果没有定义变量,容易删除/下信息,或家目录下的信息,危险 path=/tmp if [ -e $path ] then rm -fr $path fi
    说明:正常企业删除脚本 path=/tmp find ${path-/tmp} -type f -name "*.log" -mtime +7|xargs rm -f
    说明:利用find方式,如果path变量不存在,就用/tmp目录进行替换 ,没有path变量表示没有path=/tmp这行信息,即不定义path

    ===========================================================================

    扩展知识学习:bash 中变量子串说明:

    Parameter Expansion

    字符 ‘$’ 引入了参数扩展,命令替换和算术扩展。要扩展的参数名或符号可能包含在花括号中,花括号可选的,但是可以使得 要扩展的变量不会与紧随其后的字符合并,成为新的名称。

    使用花括号的时候,匹配的右括号是第一个 ‘}’,并且它没有被反斜杠引用或包含在一个引用的字符串中,也没有包含在一个嵌入的算术扩展,命令替换或是参数扩展中。

    ${parameter}

    被替换为 parameter 的值。如果 parameter 是一个位置参数,并且数字多于一位时;或者当紧随 parameter 之后有不属于名称一部分的字符时,都必须加上花括号。

    如果 parameter 的第一个字符是一个感叹号,将引进一层间接变量。 bash 使用以 parameter 的其余部分为名的变量的值作为变量的名称;接下来新的变量被扩展,它的值用在随后的替换当中,而不是使用 parameter 自身 的 值 。 这 也 称 为 indirect expansion(间接扩展). 例外情况是下面讲到的 ${!prefix*}。

    下面的每种情况中,word 都要经过波浪线扩展,参数扩展,命令替换和算术扩展。如果不进行子字符串扩展,bash 测试一个没有定义或值为空的参数;忽略冒号的结果是只测试未定义的参数。

    ${parameter:-word}

    Use Default Values(使用默认值)。如果 parameter 未定义或值为空,将替换为 word 的扩展。否则,将替换为 parame ter 的值。

    ${parameter:=word}

    Assign Default Values(赋默认值)。如果 parameter 未定义或值为空, word 的扩展将赋予 parameter. parameter 的值将被替换。位置参数和特殊参数不能用这种方式赋值。

    ${parameter:?word}

    Display Error if Null or Unset(显示错误,如果未定义或值为空)。如果 parameter 未定义或值为空,word (或一条信

    息,

    如果 word 不存在) 的扩展将写入到标准错误;shell 如果不是交互的,则将退出。否则, parameter 的值将被替换

    ${parameter:+word}

    Use Alternate Value(使用可选值)。如果 parameter 未定义或非空,不会进行替换;否则将替换为 word 扩展后的值。

    ${parameter:offset}

    ${parameter:offset:length}

    Substring Expansion(子字符串扩展)。扩展为parameter 的 多 length 个字符,从 offset 指定的字符开始。如果忽略了 length,

    扩展为 parameter 的子字符串,从 offset 指定的字符串开始。length 和 offset 是算术表达式 (参见下面的 ARITHMETIC EVALUATION 算术求值段落)。

    length 必须是一个大于等于 0 的数值。如果 offset 求值结果小于 0,值将当作从 parameter 的值的末尾算起的偏移量。

    如果 parameter 是 @,结果是 length 个位置参数,从 offset 开始。

    如果 parameter 是一个数组名,以 @ 或 * 索引,结果是数组的 length 个成员,从 ${parameter[offset]} 开始。子字符串的下标是从 0 开始的,除非使用位置参数时,下标从 1 开始。

    ​ ${!prefix*}

    ​ 扩展为名称以 prefix 开始的变量名,以特殊变量 IFS 的第一个字符分隔。

    ​ ${#parameter}

    ​ 替换为 parameter 的值的长度 (字符数目)。如果 parameter 是 * 或者是 @, 替换的值是位置参数的个数。如果 parameter 是一个数组名,下标是 * 或者是 @, 替换的值是数组中元素的个数。

    ​ ${parameter#word}

    ​ ${parameter##word}

    ​ word 被扩展为一个模式,就像路径扩展中一样。如果这个模式匹配 parameter 的值的起始,那么扩展的结果是将 param eter 扩展后的值中,短的匹配 (‘‘#’’ 的情况) 或者 长的匹配 (‘‘##’’的情况) 删除的结果。如果 parameter 是 @ 或者是 *, 则模式删除操作将依次施用于每个位置参数, 后扩展为结果的列表。如果 parameter 是一个数组变量,下标 是 @ 或者是 *, 模式删除将依次施用于数组中的每个成员, 后扩展为结果的列表。

    ​ ${parameter%word}

    ​ ${parameter%%word}

    ​ word 被扩展为一个模式,就像路径扩展中一样。如果这个模式匹配 parameter 扩展后的值的尾部,那么扩展的结果是将 parameter 扩展后的值中, 短的匹配 (‘‘%’’ 的情况) 或者 长的匹配 (‘‘%%’’的情况) 删除的结果。如果

    parameter

    ​ 是 @ 或者是 *, 则模式删除操作将依次施用于每个位置参数, 后扩展为结果的列表。如果 parameter 是一个数组变量 ,下标是 @ 或者是 *, 模式删除将依次施用于数组中的每个成员, 后扩展为结果的列表。

    ​ ${parameter/pattern/string}

    ​ ${parameter//pattern/string}

    ​ patterm 被扩展为一个模式,就像路径扩展中一样。parameter 被扩展,其值中 长的匹配 pattern 的内容 被 替 换 为 string。在第一种形式中,只有第一个匹配被替换。第二种形式使得 pattern 中所有匹配都被替换为 string。如果 patterneter 以 # 开始,它必须匹配 parameter 扩展后值的首部。如果 pattern 以 % 开始,它必须匹配 parameter 扩展后 值

    ​ 的 尾部。如果 string 是空值,pattern 的匹配都将被删除, pattern 之后的 / 将被忽略。如果 parameter 是 @ 或者

    ​ 是 *, 则替换操作将依次施用于每个位置参数, 后扩展为结果的列表。如果 parameter 是一个数组变量,下标是 @ 或

    ​ 者是 *, 模式删除将依次施用于数组中的每个成员, 后扩展为结果的列表

    (常见计算命令: (()) let expr bc $[] 总计5种)

    ===========================================================================

    变量的数值计算

    ①(())用法:(此法常用,建议使用,效率较高)

    如果执行简单的整数运算,只需将特定的算术表达式用$(())即可

    shell的算术运算符号常置于$((....))的语法中,类似于双引号功能,但内嵌双引号无需转译

    举例说明数据计算:
    范例一

    [root@MySQL 01]# ((a=1+23-4%3))
    [root@MySQL 01]# echo $a                                 将计算公式赋值给a在括号中,调用a输出计算值
    8
    [root@MySQL 01]# echo $((1+2
    3-4%3))        不将计算公式赋值给任何变量,直接调用计算公式作为变量
    8
    [root@MySQL 01]# myvar=99
    [root@MySQL 01]# echo $((myvar+1))
    100
    [root@MySQL 01]# echo $((myvar-1))
    98
    [root@MySQL 01]# echo $((myvar-1    )) 98
    [root@MySQL 01]# echo $((100/5)) 
    20
    [root@MySQL 01]# echo $((100+5))
    105
    [root@MySQL 01]# echo $((100*5))
    500
    [root@MySQL 01]# echo $((100**5)) 10000000000
    [root@MySQL 01]# echo $((100%5))
    0

    举例说明数据计算:范例二

    [root@moban scripts]#  ((a=1+2**3-4%3))
    [root@moban scripts]# echo $a
    8
    [root@moban scripts]# echo $((a+=1))
    9
    [root@moban scripts]# echo $a 9
    [root@moban scripts]# echo $((a++))
    9
    [root@moban scripts]# echo $a
    10
    [root@moban scripts]# echo $((a++))
    10
    [root@moban scripts]# echo $a 11
    [root@moban scripts]# echo $((++a))
    12
    [root@moban scripts]# echo $a
    12
    [root@moban scripts]# echo $((--a))
    11
    [root@moban scripts]# echo $a
    11
    说明:变量a在前,表达式的值为a,然后a自增或自减,变量a在符号后,表达式值自增或自减,然后a值自增或自减。

    举例说明数据计算:
    范例三

    #!/bin/bash
    a=6
    b=2
    echo "a-b =$(( $a - (b ))" echo "a+b =)(( $a + (b ))" echo "a*b =)(( $a * (b ))" echo "a/b =)(( $a / (b ))" echo "a**b =)(( $a ** (b ))" echo "a%b =)(( $a % $b ))"
    [root@moban ~]# sh heqing.sh
    执行脚本生成计算结果
    a-b =4 a+b =8 a*b =12 a/b =3 a**b =36 a%b =0
    [root@MySQL 01]# cat test2.sh 编辑传参脚本,可以输入变量,输出结果

    !/bin/bash a=$1

    b=(2 echo "a-b =)(( $a - (b ))" echo "a+b =)(( $a + (b ))" echo "a*b =)(( $a * (b ))" echo "a/b =)(( $a / (b ))" echo "a**b =)(( $a ** (b ))" echo "a%b =)(( $a % $b ))"

    =========================================================================== 扩展知识作业:

    网友的例子:

    http://chenhao6.blog.51cto.com/6228054/1232070 http://zhangbo.blog.51cto.com/350645/1172900 http://blog.163.com/shaohj_1999@126/blog/static/634068512011388519129/ 作业:本周每人完成一个简单的四则运算计算器功能

    计算器脚本方法一

    cat bc.sh
    echo $(($1$2$3))
    cat bc.sh echo $(($1))

    计算器脚本方法二

    [root@moban scripts]# cat jisuanqi.sh

    !/bin/bash a=$1

    x=$2
    b=(3 echo ")a(x)b=((()a $x $b))"

    ===========================================================================

    ②let命令的用法

    ​ 格式:let 赋值表达式 (let赋值表达式功能等同于:((赋值表达式)))举例说明数据计算:范例一 [root@MySQL 01]# i=1
    [root@MySQL 01]# let i=i+100 用let计算后面的表达式,不会影响原有定义的变量
    [root@MySQL 01]# echo $i 101

    说明:不加let时,后面i的变量不进行运算,加let表示运算后边的变量i=i+100

    ③expr(evaluate expressions)命令的用法

    expr命令一般用于整数值,但也可用于字符串,用来求表达式变量的值,同时expr是一个手工命令计数器****举例说明用法:范例一

    [root@moban scripts]# expr 2 + 2
    4
    [root@moban scripts]# expr 2 * 2
    4
    说明:expr可以直接到计算器使用
              运算符及计算的数字左右都有空格,使用乘号时,必须用反斜线屏蔽其特定含义。
              因为shell可能会误解信号的含义
    [root@MySQL 01]# i=0
    [root@MySQL 01]# i=expr $i + 1
    [root@MySQL 01]# echo $i
    1
    说明:在变量中引用expr命令,将命令复制给变量
    expr $[2+3] 5 expr $[23] 6 echo ([2+3] 5 说明:利用)[]写法进行数值运算举例说明用法:范例二
    if expr "$1" : ".
    .pub" &>/dev/null
      then
       echo "you are using $1" else
       echo "pls use *.pub file"
    fi
    说明:利用expr做文件的名称比较,如果传参的$1的文件信息扩展名为.pub,表示为真,否则为假
    [root@MySQL 01]# cat judge_int.sh
    read -p "Pls input:" a expr $a + 1 &>/dev/null
    [ $? -eq 0 ] && echo int||echo chars

    说明:利用expr功能判断一个输入的数字是否为整数

    举例说明用法:范例三

    [root@MySQL 01]# chars=seq -s" " 100
    [root@MySQL 01]# echo ((expr length ")chars") 291

    说明:利用expr命令判断字符串的长度

    ④bc命令的用法****(可以进行小数的运算)

    ​bc是unix下的计算器, 简单的方法是直接bc进入到计算模式,或echo 1.1+4.1|bc的用法
    echo "scale=3;5.23/3.13"|bc ---做除法运算,取小数点后3位
    echo "obase=2;8"|bc ---10进制8转换成2进制 echo "obase=16;20"|bc ---10进制20转换成16进制

    计算表达式案例一:

    通过一条命令计算输出1+2+3..+10的表达式,并计算出结果,使用bc计算?
    输出内容如:1+2+3+4+5+6+7+8+9+10=55
    [root@MySQL 01]# echo "seq -s '+' 10="(((`seq -s "+" 10`)) [root@MySQL 01]# echo "`seq -s '+' 10`=")((10*(10+1)/2))
    1+2+3+4+5+6+7+8+9+10=55                                                              方法一:(())方法
    [root@MySQL 01]# echo seq -s '+' 10=seq -s "+" 10|bc
    1+2+3+4+5+6+7+8+9+10=55                                                              方法二:bc方法
    [root@MySQL 01]# echo seq -s '+' 10=seq -s " + " 10|xargs expr
    1+2+3+4+5+6+7+8+9+10=55                                                              方法三:expr方法
    [root@MySQL 01]# echo {1..9}"+" 10 =echo {1..9}"+" 10|bc|sed 's# ##g'
    1+2+3+4+5+6+7+8+9+10=55                                                              方法四:三剑客方法

    总结:bc的独有特点是支持小数运算和整数运算

    ===========================================================================

    扩展知识:小数运算利用awk命令

    echo "$NEWCONN1 $NEWCONN2" |awk '{print ($2-$1)}' awk也可以计算小数…

    ===========================================================================

    ⑤$[]的计算用法

    [root@MySQL 01]# i=1
    [root@MySQL 01]# i=$[ i + 1]
    [root@MySQL 01]# echo $i 2 echo ([1+3] 4 小结: (()) let expr bc(小数awk),)[]
    扩展知识: 用shell脚本实现杨辉三角的3个实例(第一种为重点h) http://oldboy.blog.51cto.com/2561410/756234

    ===========================================================================

    课后作业:

    1、shell脚本基础,shell介绍,重要性

    2、写脚本规范,脚本的建立和执行。

    3、 shell,php,perl,python特点及区别

    4、 全局变量、普通变量的定义规范,定义方法

    5、 特殊变量,位置变量,进程状态变量

    6、 变量的字串知识

    7、 变量的数值计算:

    (()),let,expr,bc(小数awk),$[]
    预习:
    1、条件测试

    2、 if语句

    3、 case语句

    4、 while循环

    =========================================================================== 附录扩展脚本 修改eth0接口的ip地址的脚本
    [root@bash_1 mine]# cat modify_eth0_ip.sh

    /bin/bash

    if [ -z "$1" ];then
    echo "Please Enter eth0 New IP Address"
    exit
    else
    sed -i "s#IPADDR=.*#IPADDR=$1#g" /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/init.d/network restart
    fi [root@bash_1 mine]# ===========================================================================

    人的一生或多或少都在为一些事情努力着,有目标的人生是精彩的!朋友请不要在原地画圈圈,该行动了!
  • 相关阅读:
    JavaScript 倒计时脚本
    SQL Server 中的事务和锁
    Asp.net MVC 3 开发企业网站系统仿照博客园部分功能总体设计
    Windows RT 应用程序开发介绍培训的讲义
    Wcf异步调用简单示例
    asp.net搜索引擎(网络爬虫)设计及研发
    Twitter Storm RealLife App 排错记
    写个软件来防止服务器网站CPU百分百
    ALinq Dynamic
    .NET的跨平台调用一例(PreserveSig)
  • 原文地址:https://www.cnblogs.com/ronglianbing/p/11718303.html
Copyright © 2011-2022 走看看