zoukankan      html  css  js  c++  java
  • shell编程之变量

    一、变量

    1.变量的命名

    shell中的变量必须以字母或者下划线开头,后面可以跟数字、字母和下划线,变量长度没有限制。

    #正确的变量命名

    firstname

    FIRSTNAME

    _helloworld

    Fullname

    big_data

    Fullname

    Person01

    #错误的变量命名

    51paly #变量不能以数字开头

    *badname #变量不能以特殊字符开头

    PS1 #变量不能以特殊字符开头

    for #变量不能使用shell关键字

    按照以上的变量命名规则定义变量abc,从理论上来说是可行的,但是一个好的习惯是变量最好能表明它代表的含义。比如说Student_ID,一看就知道它所表达的是“学号"的意思,绝对比number这种模棱两可的变量要清晰得多名,不仅看代码的人觉得简单明了,而且有利于后期的代码维护。更好地习惯则是加上一些注释,但是也不要太过拘泥,如下所示:

    #定义学号   #使用注释解释变量使后期阅读更为清晰

    Student_ID

    #定义日期 #这种注释就显得有所拘泥

    DATE

    2.变量的赋值和取值

    #定义变量:变量名=变量值

    #注意点一:变量名和变量值之间用等号紧紧相连,之间没有任何空格

    [root@Cfhost-170820-UCNK ~]# name=john
    [root@Cfhost-170820-UCNK ~]# name = john
    -bash: name: command not found
    [root@Cfhost-170820-UCNK ~]# name="john"

    #注意点二:当变量中有空格时必须用引号括起,否则会出现错误

    #其中的引号可以是双引号,也可以是单引号

    [root@Cfhost-170820-UCNK ~]# name="john wang"
    [root@Cfhost-170820-UCNK ~]# name=john wang
    -bash: wang: command not found

    变量取值很简单,只需要在变量名前加上$符号即可,严谨一点的写法是${},如下所示:

    [root@Cfhost-170820-UCNK ~]# echo $name
    john wang
    [root@Cfhost-170820-UCNK ~]# echo ${name}
    john wang

    #使用${}获取变量值是一种相对比较保险的方式

    [root@Cfhost-170820-UCNK ~]# name=john
    [root@Cfhost-170820-UCNK ~]# name1="$name"
    [root@Cfhost-170820-UCNK ~]# echo $name1
    john
    [root@Cfhost-170820-UCNK ~]# name1='$name'
    [root@Cfhost-170820-UCNK ~]# echo name1
    name1

    由于Shell具有“弱变量"的特性,因此即便在没有预先声明变量的时候也可以引用的,而且没有任何报错或提醒,这可能会造成脚本中引用不正确的变量,从而导致脚本异常,但是却很难找出原因。在这种情况下,可以设置脚本运行时必须遵循“先声明再使用"的原则,这样一旦脚本中出现使用未声明的变量的情况则立刻报错。

    [root@Cfhost-170820-UCNK ~]# echo $unDefinedVar

    #因为该变量未声明,所以值为空,但没有任何报错

    #设置变量必须先声明再使用

    [root@Cfhost-170820-UCNK ~]# shopt -s -o nounset
    [root@Cfhost-170820-UCNK ~]# echo $unDefinedVar
    -bash: unDefinedVar: unbound variable

    3.取消变量

    [root@Cfhost-170820-UCNK ~]# name=john
    [root@Cfhost-170820-UCNK ~]# echo $name
    john #此时变量有值

    [root@Cfhost-170820-UCNK ~]# unset name
    [root@Cfhost-170820-UCNK ~]# echo $name
    -bash: name: unbound variable

    #报错为没有绑定变量

    #取消函数

    unset_function(){
    echo "Hello,World"

    }

    unset unset_function

    unset_function #由于函数已经被取消,这里调用会出错

    4.特殊变量

    Shell中还有一些预先定义的特殊只读变量,它们的值只有在脚本运行时才能确定。首先是”位置参数“,位置参数的命名简单直接,比如,脚本本身为$0,第一个参数为$1,第二个参数为$2,第三个参数为$3,以此类推。当位置参数的个数大于9时,需要用${}括起来标识,比如说第10个位置参数应该记为${10}。另外,$#表示脚本参数的个数总和,$@或$*表示脚本的所有参数。请看下面示例:

    [root@Cfhost-170820-UCNK ~]# cat posion.sh
    #!/bin/bash
    echo "This script is name is: $0"
    echo "$# Parameters in total"
    echo "All parameters list as: $@"
    echo "The first parameter is $1"
    echo "The second parameter is $2"
    echo "The third parameter is $3"
    [root@Cfhost-170820-UCNK ~]# bash posion.sh a b c
    This script is name is: posion.sh
    3 Parameters in total
    All parameters list as: a b c
    The first parameter is a
    The second parameter is b
    The third parameter is c

    脚本或命令返回值:$?

    在管理员登录到系统中交互式地输入命令时,系统也会及时在屏幕上输出内容给予反馈。比如说本想使用ifconfig查看网卡状态,但是将命令错写成ifconfi,系统会立刻给出command not found 的提示,这种提示确实能让管理员感觉到系统非常友好。

    [root@Cfhost-170820-UCNK ~]# ifconfi
    -bash: ifconfi: command not found

    但是在很多后台脚本是需要每天自动运行的,比如说每天凌晨两点的数据库备份。在这种情况下一旦出错是不可能在第一时间知道的。那靠什么判断出错呢?

    再考虑一个场景:有些自动备份脚本在按时完成本地数据备份后,还会复制一份放到远程主机上(通过scp就可以做到)。不过在复制前需要先确认远程主机是否还”活着",这可以通过ping远程主机做到。如果能ping通则进行复制,如果ping不通则采取其他动作。这里又如何判断是否ping成功了呢?

    这时就需要借助命令的返回值来判断了。Linux中规定正常退出的命令和脚本应该以0作为返回值,任何非0的返回值都表示命令未正确退出或未正常执行。

    在第一个例子中,输错命令后立即查看当时特殊变量$?的值为127;第二个例子中,ping不通某个地址时查看当时的$?值为1.注意,$?永远是上一个命令的返回值,所以要查看某个

    命令的返回值必须在运行该命令后立即查看$?。在自动化脚本中,也可以通过$?变量的值判断之前命令的执行状态,从而采取不同的动作。

    #输入错误的命令时的返回值

    [root@Cfhost-170820-UCNK ~]# ifconfi
    -bash: ifconfi: command not found
    [root@Cfhost-170820-UCNK ~]# echo $?
    127

     #尝试ping主机ping不通时的返回值

    [root@Cfhost-170820-UCNK ~]# ping 192.168.160.66 -c 1
    PING 192.168.160.66 (192.168.160.66) 56(84) bytes of data.

    --- 192.168.160.66 ping statistics ---
    1 packets transmitted, 0 received, 100% packet loss, time 10000ms

    [root@Cfhost-170820-UCNK ~]# ^C
    [root@Cfhost-170820-UCNK ~]# echo $?
    130

    5.数组

    数组是一种特殊的数据结构,其中每一项被称为一个元素,对于每个元素,都可以用索引方式取出元素的值。使用数组的典型场景是一次性要记录很多类型相同的数据时(但不是说一定要相同,因为Shell变量是弱类型的,并不要求数组的每个元素都是相同类型)。比如,为了记录班级中所有人的计算机成绩,如果不用数组来处理就只能定义所有人成绩的变量,这就会显得非常繁琐。Shell中的数组对元素个数没有限制,但是只支持一维数组,这一点和许多语言不同。

    a.数组的定义

    数组的定义方法如下:用declare命令定义数组Array,并将第一个元素赋值为0,第二个元素赋值为1,其下标(也就是索引)则分别是0和1(记住数组的索引从0开始计数的),然后打印出第一个元素的值

    #定义名为Array的索引数组

    [root@Cfhost-170820-UCNK ~]# declare -a Array

    #数组的下标从0开始计数,定义了第一个元素值为0,第二个元素值为1

    [root@Cfhost-170820-UCNK ~]# Array[0]=0
    [root@Cfhost-170820-UCNK ~]# Array[1]=1

    如果说数组Array的前两个元素“类型相同"(严格意义上这么说是不对的),那么第三个元素就显得”另类"了:赋值为一个字符串。这又一次验证了Shell变量是弱类型的,这在很多语言中是不可能的。

    [root@Cfhost-170820-UCNK ~]# Array[2]="HelloWorld"

    和其他变量一样,Shell对于数组变量的声明也非常宽松,而且随时都可以根据需要增加变量中的元素。相比其他语言,Shell的数据更为灵活。在很多语言中,一旦对数组进行初始化就不能改变其大小了。

    [root@Cfhost-170820-UCNK ~]# declare -a Array
    [root@Cfhost-170820-UCNK ~]# Array[0]=0
    [root@Cfhost-170820-UCNK ~]# Array[1]=1
    [root@Cfhost-170820-UCNK ~]# Array[2]"HelloWorld"
    -bash: Array[2]HelloWorld: command not found
    [root@Cfhost-170820-UCNK ~]# Array[2]="HelloWorld"
    [root@Cfhost-170820-UCNK ~]# declare -a Name=('john','sue')
    [root@Cfhost-170820-UCNK ~]# Name[2]='wang'
    [root@Cfhost-170820-UCNK ~]# Name=('john' 'sue')
    [root@Cfhost-170820-UCNK ~]# Score=([3]=3 [5]=5 [7]=7)

    #数组在创建的时候同时赋值

    [root@Cfhost-170820-UCNK ~]# declare -a Name=('john' 'sue')

    #增加元素

    [root@Cfhost-170820-UCNK ~]# Name[2]='wang'

    #更简单的创建数组的方式--不使用declare关键字

    [root@Cfhost-170820-UCNK ~]# Name=('john' 'sue')

    还可以给特定的元素赋值。下面的实例就是只对第四个、第六个、第八个元素进行赋值

    #跳号赋值

    [root@Cfhost-170820-UCNK ~]# Score=([3]=3 [5]=5 [7]=7)

    #数组取值:知道了如何定义数组和赋值元素后,下面就要了解数组一些常见操作。最简单的操作就是数组取值,其格式为:${数组名[索引]}.比之前定义的数组Array、Name为例,取值演示如下·:

    [root@Cfhost-170820-UCNK ~]# echo ${Array[0]}
    0
    [root@Cfhost-170820-UCNK ~]# echo ${Array[2]}
    HelloWorld
    [root@Cfhost-170820-UCNK ~]# echo ${Name[0]}
    john
    [root@Cfhost-170820-UCNK ~]# echo

    [root@Cfhost-170820-UCNK ~]# echo ${Name[1]}
    sue

    #指定索引,只能取单个值,要是想一次性取出所有元素的值,可以采取以下两种方式:
    [root@Cfhost-170820-UCNK ~]# echo ${Array[@]}
    0 1 HelloWorld
    [root@Cfhost-170820-UCNK ~]# echo ${Array[*]}
    0 1 HelloWorld

    从表面上看两者没有什么区别,但是${Array[@]}得到的是以空格隔开的元素值,而${Array[*]}的输出是整个字符串。

    数组长度:即数组个数。利用"@"或"*“字符,可以将数组扩展成列表,然后使用"#"来获取数组元素的个数,如下所示:

    [root@Cfhost-170820-UCNK ~]# echo ${#Array[@]}
    3
    [root@Cfhost-170820-UCNK ~]# echo ${#Array[*]}
    3

    如果某个元素是字符串,还可以通过指定索引的方式获得该元素长度,如下所示:

    [root@Cfhost-170820-UCNK ~]# echo ${#Array[2]}
    10

     数组截取:可以截取某个元素的一部分,对象可以是整个数组或某个元素。

    #取出数组的第一、第二个元素

    [root@Cfhost-170820-UCNK ~]# echo ${Array[@]:1:2}
    1 HelloWorld

    #取出第二个元素从第0个字符开始连续5个字符
    [root@Cfhost-170820-UCNK ~]# echo ${Array[2]:0:5}
    Hello

    #l连接数组:将n个数组进行拼接操作

    [root@Cfhost-170820-UCNK ~]# Conn=($Array[@] ${Name[@]})
    [root@Cfhost-170820-UCNK ~]# echo ${Conn[@]}
    0[@] john sue

    #取消数组或元素:和取消一般变量一样,取消一个数组的方式也可以使用unset命令

    #取消数组中的一个元素
    [root@Cfhost-170820-UCNK ~]# unset Array[1]

    #取消整个数组

    [root@Cfhost-170820-UCNK ~]# echo ${Array[@]}
    0 HelloWorld
    [root@Cfhost-170820-UCNK ~]# unset Array
    [root@Cfhost-170820-UCNK ~]# echo

    [root@Cfhost-170820-UCNK ~]# 4{Array[@]}
    -bash: 4{Array[@]}: command not found
    [root@Cfhost-170820-UCNK ~]# echo ${Array[@]}

     6.只读变量

    只读变量又称常量,是通过readonly内建命令创建的变量。这种变量在声明时就·要求赋值,并且之后无法修改,这和之前讲的使用declare -r 声明只读变量的效果是一致的。

    [root@Cfhost-170820-UCNK ~]# readonly RO=100
    [root@Cfhost-170820-UCNK ~]# RO=200
    -bash: RO: readonly variable

    7.变量的作用域

    变量的作用域又叫命名空间,表示变量的上下文。相同的变量可以在多个命名空间中定义,并且彼此之间互不干涉,所以在一个新的命名空间中可以自定义任何变量,因为所定义的变量都只在各自命名空间中。

    在Linux系统中,不同进程ID的shell默认为一个不同的命名空间。

    Shell变量的作用域是在本Shell内,属于本Shell的全局变量,也就是从定义该变量的地方开始到结束,或到主动使用unset删除该变量的地方为止。在变量的作用域内,该变量是可见的,在函数内对变量也是可以访问的、可修改的,这和C语言不同。

  • 相关阅读:
    【刷题】BZOJ 1036 [ZJOI2008]树的统计Count
    【刷题】BZOJ 1180 [CROATIAN2009]OTOCI
    【刷题】BZOJ 1453 [Wc]Dface双面棋盘
    【刷题】BZOJ 4025 二分图
    【模考】2018.04.08 Connection
    【模考】2018.04.08 Travel
    【刷题】BZOJ 4825 [Hnoi2017]单旋
    【刷题】洛谷 P3613 睡觉困难综合征
    【刷题】BZOJ 3668 [Noi2014]起床困难综合症
    CSS3_边框 border 详解_一个 div 的阴阳图
  • 原文地址:https://www.cnblogs.com/youcong/p/7906804.html
Copyright © 2011-2022 走看看