• shell脚本之变量与状态码


    目录:

       前言

    如何创建一个脚本

    脚本调试

    变量相关

    变量的命令规则

    bash中变量的种类

    本地变量

    环境变量

    只读和位置变量

    位置变量

    查询变量

    进程的退出状态与状态码

    前言

    linux管理中,shell脚本很是重要,它可以帮助我们完成很多繁琐的工作,专注于更重要的事情上来,脚本的学习也是我们学习linux中所要遇到的比较困难的部分,因为它需要对vim,正则,逻辑,程序化语言有一定的熟悉,shell编程是过程式,解释执行的。它包括各种系统指令的组合,数据存储(变量,数组)、表达式、语句。

       shell脚本中,包含一些命令或声明,并符合一定格式的文本文件,在首行是shebang机制,如:

    #!/bin/bash

    #!/usr/bin/python

    #!/usr/bin/perl

    脚本在开头查找执行本脚本的程序,此程序就在第一行命令。Shell脚本经常用于自动化常用命令,执行系统管理和故障排除,创建简单的应用程序,处理文本或文件。

    如何创建一个脚本

    第一步,使用文本编辑器(vim)创建一个文件,一般都是以.sh结尾,在第一行必须包括shell声明#!(即shebang机制)我们一般使用#!/bin/bash

    [root@CT71 bin]# vim test.sh
     1 #!/bin/bash
     2 ~                                                                                                    
     3 ~                                                                                                    
     4 ~                                                                                                    
     5 ~                                                                                                    
     6 ~                                                                                                    
     7 ~                                                                                                    
     8 ~                                                                                                    
     9 ~                                                                                                    
    10 ~                                                                                                    
    11 ~                                                                                                    
    12                                                                                                 
    13 -- INSERT --                                                                   1,12   All

    第二步,添加注释,shell脚本中的注释都是以#开头,后面跟上注释内容(一般注释写什么,我们一会儿就会说到)

    1 #!/bin/bash
    2 #Filename: test.sh
    3 #Revision: 1.0
    4 #Date: 2017-8-2
    5 #Author: hahaha
    6 #Description: ################ 
    ~
    ~
    ~

     第三步,编写脚本内容,脚本内容可以写我们常用的一些命令,比如查找我们磁盘中使用量最大的百分比等

      1 #!/bin/bash
      2 #Filename: disk.sh
      3 #Revision: 1.0
      4 #Date: 2017-8-2
      5 #Author: hahaha
      6 #Dessciption: 
      7 
      8 df | grep "dev/sd" | tr -s " " % | cut -d"%" -f5 | sort -nr | head -1
    ~                                                                                                    
    ~                                                                                                    
    ~                                                                                                    
    ~                                                                                                    
    ~                      

    第四步,给予脚本执行权限,即chmod +x shellname.sh,最后我们就可以执行我们的脚本了

    [root@CT71 bin]# ll | grep "test.sh"
    -rw-r--r--. 1 root root    0 Aug  3 16:06 test.sh
    [root@CT71 bin]# chmod +x test.sh
    [root@CT71 bin]# ll | grep "test.sh"
    -rwxr-xr-x. 1 root root    0 Aug  3 16:06 test.sh 

    接下来我们说说们可以在注释里写啥东西。

    1.  第一行一般为调用使用的语言

    2.  程序名,避免更改文件名为无法找到正确的文件

    3.  版本号

    4.  更改后的时间

    5.  作者相关信息

    6.该程序的作用,及注意事项

    7. 最后是各版本的更新简要说明

    比如说:      

    1 #!/bin/bash
    2 # Filename: hello.sh
    3 # Revision: 1.1
    4 # Date: 2017/06/01
    5 # Author: wang
    6 # Description: This is the first script 

    脚本调试

    我们咋运行脚本之前,可以对脚本进行调试,这样可以保证我们的脚本出错的几率更低,一般我们常用的有两个参数:

    检测脚本中的语法错误

    bash -n /path/to/some_script

    调试执行

    bash -x /path/to/some_script

    [root@CT71 bin]# bash -x link.sh 
    + netstat -tn
    + grep tcp
    + cut -d: -f6
    + sort -nr
    + uniq -c
    + tr -s ' ' :
          1 192.168.111.1

    接下来我们开始与脚本内容相关的知识,基础知识包括变量(变量的种类,变量的命令规则,本地变量,环境变量,位置变量),执行后的状态及状态码,算数运算与赋值。

    变量相关

    shell脚本中的变量是弱类型的变量,语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换,变量无须事先定义可直接调用。

    变量的命令规则

    1.  不能使程序中的保留字:例如if, for

    2.  只能使用数字、字母及下划线,且不能以数字开头

    3. 见名知义

    4.  统一命名规则:驼峰命名法

    1 for:错误
    2 23var:错误
    3 ip_w:正确
    4 var:正确
    5 _min:正确
    6 someIp:正确

    bash中变量的种类

    根据变量的生效范围等标准:

    本地变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效

    环境变量:生效范围为当前shell进程及其子进程局部变量:生效范围为当前shell进程中某代码片断(通常指函数)

    位置变量: $1, $2, ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数

    特殊变量:

     $?, $0, $*, $@, $#,$$

     

    在这些变量中,本地变量仅对当前shell有效,对子shell是没有效的。而环境变量对当前shell及其子shell都有效,我们可以用env查询所有的环境变量,用set查询本地变量和环境,我们有一点需要知道,在linux变量声明以后会一直存在,除非我们把他们给删除掉,删除变量我们可以用unset varname

    [root@CT71 bin]# echo $A
    string
    [root@CT71 bin]# unset A
    [root@CT71 bin]# echo $A
    
    [root@CT71 bin]# set | grep "^A"
    ABRT_DEBUG_LOG=/dev/null
    删除了A变量

     

    本地变量

    设置变量:

       (1) 可以是直接字串; name=root"

    (2) 变量引用: name="$USER"

    (3) 命令引用: name=`COMMAND` name=$(COMMAND)

    引用变量:

       ${varname}

    $varname

    “$varname”

    [root@CT71 bin]# myName=BUG
    [root@CT71 bin]# echo $myName
    BUG
    [root@CT71 bin]# echo "$myName"
    BUG
    [root@CT71 bin]# echo ${myName}
    BUG

    "":弱引用,其中的变量引用会被替换为变量值

    '':强引用,其中的变量引用不会被替换为变量值,而保持原字符串

    [root@CT71 bin]# echo "$USER"
    root
    [root@CT71 bin]# echo '$USER'
    $USER

     

    转译:

    完全转译

    ""部分转译 ` ! $(""无法转译的字符)

    '' 完全转译

    转译的原因是因为有些字符在linux下有特殊含义,但是,我们又需要用到它普通意义,所以我们需要对他们转译成非特殊字符供我们使用。

    [root@CT71 app]# echo "$20.0"
    0.0
    [root@CT71 app]# echo "$20.0"
    $20.0
    [root@CT71 app]# echo '$20.0'
    $20.0
    [root@CT71 app]# echo "!ll"
    echo "ll"
    ll
    [root@CT71 app]# echo '!ll'
    !ll

    环境变量

    环境变量的声明:

       export name=value

    declare -x name=value

    环境变量的引用:

       $name

    ${name}

    在前面我们已经说过如何查看我们的变量,但是,查看环境变量的命令还有几个,如:envprintenvexportdeclare –x,在bash中还有一些内建的环境变量

    PATH:命令查找的路径

    SHELL:我们使用的shell

    USER:当前用户名

    UID:当前用户UID

    HOME:家目录

    PWD:当前工作目录

    SHLVL:当前所在的几级shell

    LANG:使用的字符集

    MAIL:邮箱路径

    HOSTNAME:主机名

    HISTSIZE:历史命令记录长度

    _:上次执行的命令

     

    [root@CT71 app]# env
    XDG_SESSION_ID=612
    HOSTNAME=CT71  -----------------------------------------------------------------------主机名
    SELINUX_ROLE_REQUESTED=
    TERM=xterm
    SHELL=/bin/bash  ---------------------------------------------------------------------使用的shell
    HISTSIZE=1000  -----------------------------------------------------------------------历史命令记录长度
    SSH_CLIENT=192.168.111.1 52880 22
    SELINUX_USE_CURRENT_RANGE=
    SSH_TTY=/dev/pts/2
    USER=root  ---------------------------------------------------------------------------当前用户名
    LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00
    ... ...
    MAIL=/var/spool/mail/root --------------------------------------------------------------邮箱路径
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin  --------------------命令查找路径
    PWD=/app  ----------------------------------------------------------------------------当前的工作目录
    LANG=en_US.UTF-8  --------------------------------------------------------------------使用的字符集
    ... ...

     SHLVL=1  -----------------------------------------------------------------------------当前所在的几级shell
     HOME=/root  --------------------------------------------------------------------------当前用户家目录
     LOGNAME=root
     SSH_CONNECTION=192.168.111.1 52880 192.168.111.110 22
     LESSOPEN=||/usr/bin/lesspipe.sh %s
     XDG_RUNTIME_DIR=/run/user/0
     OLDPWD=/root/bin
     _=/usr/bin/env  ----------------------------------------------------------------------上次执行的命令

     

    只读和位置变量

    我们可以在linux中设置只读变量,它的特点是只能声明,但不能修改和删除

    声明只读变量:

       readonly name

       declare –r name

    查看只读变量:

       readonly –p

    [root@CT71 app]# readonly H=2134
    [root@CT71 app]# H=werq
    -bash: H: readonly variable
    [root@CT71 app]# readonly -p
    declare -r BASHOPTS="checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath"
    declare -ir BASHPID
    declare -r BASH_COMPLETION_COMPAT_DIR="/etc/bash_completion.d"
    declare -ar BASH_REMATCH='()'
    declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")'
    declare -ir EUID="0"
    declare -r H="2134"
    declare -ir PPID="57929"
    declare -r S
    declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"
    declare -ir UID="0"
    [root@CT71 app]# unset -f S  删除只读变量
    [root@CT71 app]# echo $S
    
    [root@CT71 app]# 

    declare是一个shell的内建命令,用来显示所有变量属性和和值的,它还有一些常用的参数,比如上面的declare –r是用来设置只读变量的,declare –f不仅显示变量,还显示函数,还有declare –x设置环境变量等

    位置变量

    位置变量其实就是在脚本代码中调用通过命令行传递给脚本的参数。我们可以通过外在的参数传递给脚本以实现与脚本的交互操作,增强脚本功能。

       在脚本中的$1,$2,$3…分别对应着脚本外面的1个,第2个,第3参数,$0代表的是命令本身,$*是传递给脚本的所有参数,全部参数合为一个字符串

    $@是传递给脚本的所有参数,每个参数为独立字符串,$#是传递给脚本的参数的个数($@ $* 只在被双引号包起来的时候才会有差异)

    set -- 清空所有位置变量

      1 #!/bin/bash
      2 
      3 echo "$1"
    ~                                                                                                    
    ~  
    -------------------------------------------
    [root@CT71 app]# chmod +x test.sh 
    [root@CT71 app]# ll
    total 4
    -rwxr-xr-x. 1 root root 23 Aug  3 19:22 test.sh
    [root@CT71 app]# ./test.sh Hello
    Hello
      1 #!/bin/bash
      2 echo "filename :$(basename $0)"
    ~                                                                                                    
    ~                                                                                                    
    ~      
    -----------------------------------------

    [root@CT71 app]# ./test2.sh
    filename :test2.sh

      1 #!/bin/bash     #tt1.sh   
      2 ./tt2.sh "$@"
    ~                                                                                                    
    ~                 
      1 #!/bin/bash    #tt2.sh    
      2 
      3 echo "$@"
    ~             
    [root@CT71 app]# ./tt1.sh 1 2 3 4 5
    1 2 3 4 5
    ---------------------------------------------------------------------
      1 #!/bin/bash     #tt1.sh   
      2 ./tt2.sh "$#"
    ~                                                                                                    
    ~                 
      1 #!/bin/bash    #tt2.sh    
      2 
      3 echo "$#"
    ~             
    [root@CT71 app]# ./tt1.sh 1 2 3 4 5
    1

    由于我不是在PATH所在的路径下执行的脚本所以直接执行脚本是找不到的,必须要跟上确定的路径./tt2.sh就是在本目录下执行tt2.sh脚本

    查询变量

    本地变量的查询

       set (即查本地,也查环境)

    [root@CT71 app]# set | grep -C 4 "^PWD"
    PROMPT_COMMAND='printf "33]0;%s@%s:%s07" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
    PS1='[u@h W]$ '
    PS2='> '
    PS4='+ '
    PWD=/app
    SELINUX_LEVEL_REQUESTED=
    SELINUX_ROLE_REQUESTED=
    SELINUX_USE_CURRENT_RANGE=
    SHELL=/bin/bash

    环境变量的查询

    env

    printenv

    export

    declare -x

    [root@CT71 app]# printenv
    XDG_SESSION_ID=612
    HOSTNAME=CT71
    SELINUX_ROLE_REQUESTED=
    TERM=xterm
    SHELL=/bin/bash
    HISTSIZE=1000
    SSH_CLIENT=192.168.111.1 52880 22
    SELINUX_USE_CURRENT_RANGE=
    ... ...

    进程的退出状态与状态码

    我们在系统中没执行一个命令都会开辟一个进程,配置一个PID,当程序运行结束后,即进程结束后,都会返回一个值给变量“?”,通过返回的值,我们就可以了解到这个进程执行的结果如何,在返回的中,0 代表执行成功,1-255代表着不同的失败$?变量保存着最近的命令执行后的状态。

    除了程序自动的赋值外,我们也可以手动自定义程序退出的状态码,特别是在我们写脚本时,通过条件语句进行判断时,自定义的退出码就派上大用场。

    自定义退出状态码:

       exit[n] n={1..255}

    注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

    注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

      1 #!/bin/bash
      2 
      3 echo "Myname is Tony!"
      4 
      5 exit 1
      6 
      7 echo "Show my name"
    ~                                                                                                    
    ~  
    --------------------------------------------------
    [root@CT71 app]# chmod +x tt3.sh 
    [root@CT71 app]# ./tt3.sh 
    Myname is Tony!

    在这我们多说一点东西,如何查看进程以及PID,这里有几个变量和命令,我们来看一下:

    变量$$:查看当前的PID

    PPID:查看父进程的PID

    SHLVL:显示当前的shell是几级shell

    pstree:显示进程树

        -p:同时显示进程的PID

       ps –ef :显示进程信息

     

    [root@CT71 app]# echo $$
    57933
    [root@CT71 app]# echo $PPID
    57929
    [root@CT71 app]# pstree -p | grep -C 2 "bash"
               |                `-{rsyslogd}(2281)
               |-smartd(577)
               |-sshd(1401)---sshd(57929)---bash(57933)-+-grep(61485)
               |                                        `-pstree(61484)
               |-systemd-journal(367)
    [root@CT71 app]# echo $SHLVL
    1
    [root@CT71 app]# ps -ef | grep "bash"
    root        607      1  0 Jul31 ?        00:00:14 /bin/bash /usr/sbin/ksmtuned
    root      57933  57929  0 14:09 pts/2    00:00:01 -bash
    root      61495  57933  0 20:05 pts/2    00:00:00 grep --color=auto bash

     

     

  • 相关阅读:
    php 基本连接mysql数据库和查询数据
    HTTP/2 简介
    MySQL数据库 utf-8与utf8mb4
    AJAX请求中出现OPTIONS请求
    精力充沛的管理者,要不要“闲”下来?
    【转】微信开发出现“该公众号暂时无法提供服务,请稍后再试”的坑
    Nginx笔记(一):安装
    Tomcat分析
    Redis集群搭建与使用
    微信JS-SDK实现上传图片功能
  • 原文地址:https://www.cnblogs.com/duzhaoqi/p/7280056.html
Copyright © 2020-2023  润新知